Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Converting String to and from ByteBuffer and associated problems

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:

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!

like image 733
DivideByHero Avatar asked Aug 09 '09 22:08

DivideByHero


People also ask

How do you write and read from ByteBuffer in Java?

The methods get() and put() read and write a byte respectively at the current position and then automatically update the position. Thus, in the simplest case of just wanting to read sequentially through data in the buffer (or write data sequentially), this can be accomplished with some extremely straightforward code.

How does ByteBuffer work in Java?

ByteBuffer holds a sequence of integer values to be used in an I/O operation. The ByteBuffer class provides the following four categories of operations upon long buffers: Absolute and relative get method that read single bytes. Absolute and relative put methods that write single bytes.

What does ByteBuffer wrap do?

wrap. Wraps a byte array into a buffer. The new buffer will be backed by the given byte array; that is, modifications to the buffer will cause the array to be modified and vice versa. The new buffer's capacity and limit will be array.


Video Answer


2 Answers

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.

like image 38
Fuwjax Avatar answered Sep 21 '22 17:09

Fuwjax


Check out the CharsetEncoder and CharsetDecoder API descriptions - You should follow a specific sequence of method calls to avoid this problem. For example, for CharsetEncoder:

  1. Reset the encoder via the reset method, unless it has not been used before;
  2. Invoke the encode method zero or more times, as long as additional input may be available, passing false for the endOfInput argument and filling the input buffer and flushing the output buffer between invocations;
  3. Invoke the encode method one final time, passing true for the endOfInput argument; and then
  4. Invoke the flush method so that the encoder can flush any internal state to the output buffer.

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.

like image 80
Adamski Avatar answered Sep 20 '22 17:09

Adamski