J'utilise Java NIO pour mes connexions de socket et mon protocole est basé sur du texte. Je dois donc pouvoir convertir des chaînes en ByteBuffers avant de les écrire dans SocketChannel et reconvertir les ByteBuffers entrants. Pour Strings, j'utilise actuellement ce 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;
}
Cela fonctionne la plupart du temps, mais je me demande si c'est le moyen préféré (ou le plus simple) de faire chaque direction de cette conversion, ou s'il existe un autre moyen d'essayer. Parfois, et apparemment au hasard, les appels à encode()
et decode()
lèveront une exception Java.lang.IllegalStateException: Current state = FLUSHED, new state = CODING_END
, Ou similaire, même si j'utilise un nouvel objet ByteBuffer à chaque fois la conversion est terminée. Dois-je synchroniser ces méthodes? Un meilleur moyen de convertir entre Strings et ByteBuffers? Merci!
Découvrez les descriptions de l'API CharsetEncoder
et CharsetDecoder
- Vous devez suivre une séquence de méthodes spécifique appelle pour éviter ce problème. Par exemple, pour CharsetEncoder
:
reset
, à moins qu’il n’ait été utilisé auparavant;encode
zéro ou plusieurs fois, tant qu'une entrée supplémentaire peut être disponible, en transmettant false
pour l'argument endOfInput, en remplissant le tampon d'entrée et en vidant le tampon de sortie entre les invocations;encode
une dernière fois en passant true
pour l'argument endOfInput; et alorsflush
pour que le codeur puisse vider tout état interne dans la mémoire tampon de sortie.En passant, c’est la même approche que j’utilise pour NIO bien que certains de mes collègues convertissent directement chaque caractère en octet, sachant qu’ils utilisent uniquement l’ASCII, ce qui, j’imagine, est probablement plus rapide.
À moins que les choses changent, il vaut mieux avec
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);
}
En règle générale, buffer.hasArray () sera toujours vrai ou toujours faux en fonction de votre cas d'utilisation. En pratique, à moins que vous ne vouliez vraiment que cela fonctionne, il est prudent d'optimiser la succursale dont vous n'avez pas besoin.
Answer by Adamski est bon et décrit les étapes d’une opération de codage lors de l’utilisation de la méthode de codage général (qui utilise un tampon d’octets comme l’une des entrées).
Cependant, la méthode en question (dans cette discussion) est une variante de encoder - encoder (CharBuffer dans) . Il s'agit d'une méthode pratique qui implémente la totalité de l'opération de codage . (Veuillez consulter Java dans P.S.)
Selon la documentation, Cette méthode ne doit donc pas être invoquée si une opération de codage est déjà en cours (ce qui se passe dans le code de ZenBlender - en utilisant codeur/décodeur statique dans un environnement multithread).
Personnellement, j'aime utiliser les méthodes commodité (par rapport aux méthodes plus générales d’encodage/décodage), car elles suppriment la charge en effectuant toutes les étapes à l’écart.
ZenBlender et Adamski ont déjà suggéré plusieurs façons de le faire en toute sécurité dans leurs commentaires. Les listant tous ici:
P.S.
Références de la documentation Java: