Java:String 与 ByteBuffer 的相互转换及相关问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1252468/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java: Converting String to and from ByteBuffer and associated problems
提问by DivideByHero
I am using Java NIO for my socket connections, and my protocol is text based, so I need to be able to convert Strings to ByteBuffers before writing them to the SocketChannel, and convert the incoming ByteBuffers back to Strings. Currently, I am using this code:
我的套接字连接使用 Java NIO,并且我的协议是基于文本的,所以我需要能够在将字符串写入 SocketChannel 之前将它们转换为 ByteBuffer,并将传入的 ByteBuffer 转换回字符串。目前,我正在使用此代码:
public static Charset charset = Charset.forName("UTF-8");
public static CharsetEncoder encoder = charset.newEncoder();
public static CharsetDecoder decoder = charset.newDecoder();
public static ByteBuffer str_to_bb(String msg){
try{
return encoder.encode(CharBuffer.wrap(msg));
}catch(Exception e){e.printStackTrace();}
return null;
}
public static String bb_to_str(ByteBuffer buffer){
String data = "";
try{
int old_position = buffer.position();
data = decoder.decode(buffer).toString();
// reset buffer's position to its original so it is not altered:
buffer.position(old_position);
}catch (Exception e){
e.printStackTrace();
return "";
}
return data;
}
This works most of the time, but I question if this is the preferred (or simplest) way to do each direction of this conversion, or if there is another way to try. Occasionally, and seemingly at random, calls to encode()
and decode()
will throw a
java.lang.IllegalStateException: Current state = FLUSHED, new state = CODING_END
exception, or similar, even if I am using a new ByteBuffer object each time a conversion is done. Do I need to synchronize these methods? Any better way to convert between Strings and ByteBuffers? Thanks!
这在大多数情况下都有效,但我怀疑这是否是执行此转换的每个方向的首选(或最简单)方法,或者是否有另一种尝试方法。有时,即使我在每次转换完成时都使用一个新的 ByteBuffer 对象,调用encode()
和decode()
会抛出java.lang.IllegalStateException: Current state = FLUSHED, new state = CODING_END
异常或类似的
情况,并且看起来是随机的。我需要同步这些方法吗?在 Strings 和 ByteBuffers 之间转换的任何更好的方法?谢谢!
采纳答案by Adamski
Check out the CharsetEncoder
and CharsetDecoder
API descriptions - You should follow a specific sequence of method callsto avoid this problem. For example, for CharsetEncoder
:
查看CharsetEncoder
和CharsetDecoder
API 描述 - 您应该遵循特定的方法调用顺序来避免此问题。例如,对于CharsetEncoder
:
- Reset the encoder via the
reset
method, unless it has not been used before; - Invoke the
encode
method zero or more times, as long as additional input may be available, passingfalse
for the endOfInput argument and filling the input buffer and flushing the output buffer between invocations; - Invoke the
encode
method one final time, passingtrue
for the endOfInput argument; and then - Invoke the
flush
method so that the encoder can flush any internal state to the output buffer.
- 通过
reset
方法重置编码器,除非之前没有使用过; - 调用该
encode
方法零次或多次,只要额外的输入可用,传递false
endOfInput 参数并填充输入缓冲区并在调用之间刷新输出缓冲区; encode
最后一次调用该方法,传递true
endOfInput 参数;进而- 调用该
flush
方法,以便编码器可以将任何内部状态刷新到输出缓冲区。
By the way, this is the same approach I am using for NIO although some of my colleagues are converting each char directly to a byte in the knowledge they are only using ASCII, which I can imagine is probably faster.
顺便说一下,这与我用于 NIO 的方法相同,尽管我的一些同事在他们只使用 ASCII 的知识中将每个字符直接转换为一个字节,我可以想象这可能会更快。
回答by gurpsin
Answer by Adamski is a good one and describes the steps in an encoding operation when using the general encode method (that takes a byte buffer as one of the inputs)
Adamski 的回答很好,它描述了使用通用编码方法(将字节缓冲区作为输入之一)时编码操作中的步骤
However, the method in question (in this discussion) is a variant of encode - encode(CharBuffer in). This is a convenience method that implements the entire encoding operation. (Please see java docs reference in P.S.)
但是,所讨论的方法(在本讨论中)是 encode 的变体 - encode(CharBuffer in)。这是实现整个编码操作的便捷方法。(请参阅 PS 中的 Java 文档参考)
As per the docs, This method should therefore not be invoked if an encoding operation is already in progress(which is what is happening in ZenBlender's code -- using static encoder/decoder in a multi threaded environment).
根据文档,如果编码操作已经在进行中,则不应调用此方法(这是 ZenBlender 代码中发生的情况——在多线程环境中使用静态编码器/解码器)。
Personally, I like to use conveniencemethods (over the more general encode/decode methods) as they take away the burden by performing all the steps under the covers.
就我个人而言,我喜欢使用方便的方法(而不是更通用的编码/解码方法),因为它们通过在幕后执行所有步骤来减轻负担。
ZenBlender and Adamski have already suggested multiple ways options to safely do this in their comments. Listing them all here:
ZenBlender 和 Adamski 已经在他们的评论中提出了多种安全方式选项。在这里列出它们:
- Create a new encoder/decoder object when needed for each operation (not efficient as it could lead to a large number of objects). OR,
- Use a ThreadLocal to avoid creating new encoder/decoder for each operation. OR,
- Synchronize the entire encoding/decoding operation (this might not be preferred unless sacrificing some concurrency is ok for your program)
- 在每个操作需要时创建一个新的编码器/解码器对象(效率不高,因为它可能导致大量对象)。或者,
- 使用 ThreadLocal 避免为每个操作创建新的编码器/解码器。或者,
- 同步整个编码/解码操作(这可能不是首选,除非您的程序可以牺牲一些并发性)
P.S.
聚苯乙烯
java docs references:
java文档参考:
- Encode (convenience) method: http://docs.oracle.com/javase/6/docs/api/java/nio/charset/CharsetEncoder.html#encode%28java.nio.CharBuffer%29
- General encode method: http://docs.oracle.com/javase/6/docs/api/java/nio/charset/CharsetEncoder.html#encode%28java.nio.CharBuffer,%20java.nio.ByteBuffer,%20boolean%29
回答by Fuwjax
Unless things have changed, you're better off with
除非事情发生了变化,否则你最好
public static ByteBuffer str_to_bb(String msg, Charset charset){
return ByteBuffer.wrap(msg.getBytes(charset));
}
public static String bb_to_str(ByteBuffer buffer, Charset charset){
byte[] bytes;
if(buffer.hasArray()) {
bytes = buffer.array();
} else {
bytes = new byte[buffer.remaining()];
buffer.get(bytes);
}
return new String(bytes, charset);
}
Usually buffer.hasArray() will be either always true or always false depending on your use case. In practice, unless you really want it to work under any circumstances, it's safe to optimize away the branch you don't need.
通常 buffer.hasArray() 将始终为 true 或始终为 false,具体取决于您的用例。实际上,除非您真的希望它在任何情况下都能工作,否则优化掉不需要的分支是安全的。