Estoy usando Java NIO para mis conexiones de socket, y mi protocolo está basado en texto, por lo que necesito poder convertir Strings en ByteBuffers antes de escribirlos en SocketChannel, y convertir los ByteBuffers entrantes de nuevo en Strings. Actualmente, estoy usando este código:
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;
}
Esto funciona la mayor parte del tiempo, pero me pregunto si es la forma preferida (o la más sencilla) de realizar cada dirección de esta conversión, o si hay otra forma de intentarlo. De vez en cuando, y aparentemente de forma aleatoria, las llamadas encode()
y decode()
arrojarán una
java.lang.IllegalStateException: Current state = FLUSHED, new state = CODING_END
excepción, o similar, incluso si estoy usando un nuevo objeto ByteBuffer cada vez que se realiza una conversión. ¿Necesito sincronizar estos métodos? ¿Alguna mejor manera de convertir entre cadenas y ByteBuffers? ¡Gracias!
fuente
Respuestas:
Consulte las descripciones de la API
CharsetEncoder
yCharsetDecoder
: debe seguir una secuencia específica de llamadas a métodos para evitar este problema. Por ejemplo, paraCharsetEncoder
:reset
método, a menos que no se haya utilizado antes;encode
método cero o más veces, siempre que haya una entrada adicional disponible, pasandofalse
el argumento endOfInput y llenando el búfer de entrada y vaciando el búfer de salida entre invocaciones;encode
método una última vez, pasandotrue
por el argumento endOfInput; y entoncesflush
método para que el codificador pueda vaciar cualquier estado interno al búfer de salida.Por cierto, este es el mismo enfoque que estoy usando para NIO, aunque algunos de mis colegas están convirtiendo cada carácter directamente en un byte sabiendo que solo están usando ASCII, que puedo imaginar que probablemente sea más rápido.
fuente
A menos que las cosas hayan cambiado, estás mejor con
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); }
Por lo general, buffer.hasArray () será siempre verdadero o siempre falso dependiendo de su caso de uso. En la práctica, a menos que realmente desee que funcione bajo cualquier circunstancia, es seguro optimizar la rama que no necesita.
fuente
La respuesta de Adamski es buena y describe los pasos en una operación de codificación cuando se usa el método de codificación general (que toma un búfer de bytes como una de las entradas)
Sin embargo, el método en cuestión (en esta discusión) es una variante de encode - encode (CharBuffer en) . Este es un método conveniente que implementa toda la operación de codificación . (Consulte la referencia de documentos de Java en PS)
Según los documentos, este método no debe invocarse si una operación de codificación ya está en progreso (que es lo que está sucediendo en el código de ZenBlender, usando un codificador / decodificador estático en un entorno de subprocesos múltiples).
Personalmente, me gusta usar métodos de conveniencia (en lugar de los métodos de codificación / decodificación más generales) ya que eliminan la carga al realizar todos los pasos debajo de las cubiertas.
ZenBlender y Adamski ya han sugerido varias opciones para hacer esto de forma segura en sus comentarios. Listarlos todos aquí:
PD
referencias de java docs:
fuente