Java:将字符串与字节缓冲区相互转换以及相关的问题

我正在使用Java NIO进行套接字连接,并且我的协议是基于文本的,因此我需要能够在将字符串写入SocketChannel之前将它们转换为ByteBuffers,并将传入的ByteBuffers转换回Strings。目前,我正在使用下面的代码:

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;
}

这在大多数情况下都有效,但我质疑这是否是执行此转换的每个方向的首选(或最简单)方法,或者是否有另一种方法可以尝试。偶尔,而且似乎是随机的,调用和将引发异常或类似情况,即使我每次完成转换时都使用新的ByteBuffer对象。我是否需要同步这些方法?有没有更好的方法在字符串和字节缓冲器之间转换?谢谢!encode()decode()java.lang.IllegalStateException: Current state = FLUSHED, new state = CODING_END


答案 1

查看CharsetEncoderCharsetDecoder API说明 - 您应该遵循特定的方法调用序列以避免此问题。例如,对于 :CharsetEncoder

  1. 通过该方法重置编码器,除非以前未使用过;reset
  2. 调用方法零次或多次,只要有额外的输入可用,传入 endOfInput 参数并填充输入缓冲区并在调用之间刷新输出缓冲区;encodefalse
  3. 最后一次调用该方法,传递 endOfInput 参数;然后encodetrue
  4. 调用该方法,以便编码器可以将任何内部状态刷新到输出缓冲区。flush

顺便说一句,这与我对NIO使用的方法相同,尽管我的一些同事正在将每个字符直接转换为一个字节,因为他们只使用ASCII,我可以想象这可能更快。


答案 2

除非事情发生了变化,否则你最好

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);
}

通常 buffer.hasArray() 要么总是真,要么总是假,这取决于你的用例。在实践中,除非你真的希望它在任何情况下都能工作,否则可以安全地优化你不需要的分支。