92 votes

Java: Conversion de Chaîne vers et à partir de ByteBuffer et les problèmes associés

Je suis à l'aide de Java NIO pour mes connexions socket, et mon protocole est en mode texte, donc j'ai besoin d'être en mesure de convertir des Chaînes en ByteBuffers avant de les écrire à la SocketChannel, et le convertir en entrant ByteBuffers retour à Cordes. Actuellement, je suis en utilisant 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 la meilleure (ou la plus simple) de manière à faire de chaque direction de cette conversion, ou si il y a un autre moyen de les essayer. De temps en temps, apparemment au hasard, les appels à l' encode() et decode() va lancer une java.lang.IllegalStateException: Current state = FLUSHED, new state = CODING_END d'exception, ou similaires, même si je suis en utilisant une nouvelle ByteBuffer objet à chaque fois qu'une conversion est effectuée. Ai-je besoin de synchroniser ces méthodes? Une meilleure façon de faire les conversions entre Chaînes et ByteBuffers? Merci!

54voto

Adamski Points 29884

Découvrez l' CharsetEncoder et CharsetDecoder API descriptions - Vous devez suivre une séquence spécifique d'appels de méthode pour éviter ce problème. Par exemple, pour CharsetEncoder:

  1. Réinitialiser le codeur via l' reset méthode, à moins qu'il n'a pas été utilisé avant;
  2. Invoquer l' encode méthode de zéro ou plusieurs fois, tant qu'entrée supplémentaires peuvent être disponibles, en passant false pour les endOfInput argument et de remplissage de la mémoire tampon d'entrée et de rinçage de la mémoire tampon de sortie entre les appels;
  3. Invoquer l' encode méthode une dernière fois, en passant true pour les endOfInput argument; et puis
  4. Invoquer l' flush méthode de manière à ce que le codeur peut éliminer tout état interne de la mémoire tampon de sortie.

Par ailleurs, cette approche est la même que j'utilise pour le NIO bien que certains de mes collègues sont en train de convertir chaque caractère directement à un octet dans les connaissances qu'ils sont en utilisant uniquement des caractères ASCII, ce qui j'imagine est probablement plus rapide.

14voto

gurpsin Points 61

Réponse par Adamski est bonne et décrit les étapes d'une opération de codage lors de l'utilisation de l'générale méthode encode (qui prend un tampon d'octets comme l'une des entrées)

Cependant, la méthode en question (dans cette discussion) est une variante de coder - encoder(CharBuffer). C'est une méthode pratique qui met en œuvre l'intégralité de l'opération de codage. (Veuillez voir java docs de référence dans le P. S.)

Selon les docs, Cette méthode ne devrait donc pas être invoquée si l'encodage opération est déjà en cours (qui est ce qui se passe dans ZenBlender du code -- statique à l'aide de l'encodeur/décodeur dans un environnement multithread).

Personnellement, j'aime utiliser la commodité des méthodes (en plus de la plus générale encoder/décoder les méthodes que celles qu'ils prennent à l'écart de la charge en effectuant toutes les étapes sous les couvertures.

ZenBlender et Adamski ont déjà suggéré des manières multiples options de sécurité dans leurs commentaires. De les énumérer toutes ici:

  • Créer un nouveau codeur/décodeur objet lorsque cela est nécessaire pour chaque opération (pas efficace, car elle pourrait conduire à un grand nombre d'objets). OU,
  • Utiliser un ThreadLocal éviter de créer de nouvelles encodeur/décodeur pour chaque opération. OU,
  • Synchroniser l'ensemble de l'encodage/décodage de l'opération (cela ne pourrait pas être privilégié, à moins de sacrifier un peu de simultanéité est ok pour votre programme)

P. S.

java docs références:

  1. Coder (commodité) méthode: http://docs.oracle.com/javase/6/docs/api/java/nio/charset/CharsetEncoder.html#encode%28java.nio.CharBuffer%29
  2. Général de la méthode encode: http://docs.oracle.com/javase/6/docs/api/java/nio/charset/CharsetEncoder.html#encode%28java.nio.CharBuffer,%20java.nio.ByteBuffer,%20boolean%29

0voto

Wolkenjaeger Points 438

Comme cette question est l'un des meilleurs résultats dans Google, je suggère aussi une réponse simple pour les personnes seules à la recherche, pour la simple conversion.

Attention: je ne suis pas sur sur de codage dans cette solution. Ce n'est pas la meilleure solution, comme déjà indiqué par Christoffer.

Pour ByteBuffer:

ByteBuffer bb = ByteBuffer.wrap(inputString.getBytes()); 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X