Question

J'utilise Java NIO pour mes connexions socket, et mon protocole est basé sur du texte, donc je dois être en mesure de convertir les chaînes en ByteBuffers avant de les écrire à la SocketChannel, et convertir les ByteBuffers entrants revenir à cordes. À l'heure actuelle, 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 le meilleur moyen (ou simple) à faire chaque sens de cette conversion, ou s'il y a une autre façon d'essayer. De temps en temps, et apparemment au hasard, appelle à encode() et decode() lancera une exception java.lang.IllegalStateException: Current state = FLUSHED, new state = CODING_END, ou similaire, même si je me sers d'un nouvel objet ByteBuffer chaque fois est effectué une conversion. Ai-je besoin de synchroniser ces méthodes? Une meilleure façon de convertir entre les chaînes et ByteBuffers? Merci!

Était-ce utile?

La solution

Consultez la CharsetEncoder et CharsetDecoder descriptions API - Vous devriez suivre un séquence spécifique de la méthode appelle pour éviter ce problème. Par exemple, pour CharsetEncoder:

  1. Réinitialiser l'encodeur via la méthode reset, à moins qu'il n'a pas été utilisé auparavant;
  2. Appelez la méthode encode zéro ou plusieurs fois, aussi longtemps que l'entrée supplémentaire peut être disponible, en passant false pour l'argument endOfInput et le remplissage de la mémoire tampon d'entrée et de rinçage du tampon de sortie entre les invocations;
  3. Appelez la méthode encode une dernière fois, en passant true pour l'argument endOfInput; puis
  4. Appelez la méthode flush de sorte que le codeur peut vider tout état interne à la mémoire tampon de sortie.

Par ailleurs, c'est la même approche que je utilise pour NIO bien que certains de mes collègues se convertissent chaque ombles directement à un octet dans la connaissance qu'ils n'utilisent ASCII, que je peux imaginer est probablement plus rapide.

Autres conseils

À moins que les choses ont changé, vous êtes 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);
}

Habituellement buffer.hasArray () sera soit toujours vrai ou toujours faux selon votre cas d'utilisation. Dans la pratique, sauf si vous voulez vraiment travailler en aucun cas, il est sûr d'optimiser loin la branche que vous n'avez pas besoin.

Réponse de Adamski est bonne et décrit les étapes dans une opération de codage en utilisant le procédé général de codage (qui prend un tampon d'octets en tant que l'une des entrées)

Cependant, la méthode en question (dans cette discussion) est une variante de encode - encode (CharBuffer in) . Ceci est une méthode pratique qui implémente l'opération d'encodage . (S'il vous plaît voir docs java référence dans P.S.)

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

Personnellement, je préfère utiliser confort méthodes (sur les encode plus généraux / méthodes de décodage) car ils enlèvent la charge en effectuant toutes les étapes sous les couvertures.

ZenBlender et Adamski ont déjà suggéré plusieurs options de façons de le faire en toute sécurité ce dans leurs commentaires. les énumérer tous ici:

  • Créer un nouvel objet encodeur / décodeur en cas de besoin pour chaque opération (pas efficace car elle pourrait conduire à un grand nombre d'objets). OU,
  • Utilisez un ThreadLocal pour éviter de créer nouveau codeur / décodeur pour chaque opération. OU,
  • Synchronisez l'ensemble de l'opération de codage / décodage (cela pourrait ne pas être préféré à moins sacrifier une partie est ok pour concurrency votre programme)

P.S.

références docs java:

  1. méthode Encode (convenience): http://docs.oracle.com/javase/6/docs/api/java/nio/charset/CharsetEncoder.html#encode%28java.nio.CharBuffer%29
  2. Méthode générale encode: http://docs.oracle.com/javase/6/docs/api/java/nio/charset/CharsetEncoder.html#encode%28java.nio.CharBuffer,%20java. nio.ByteBuffer,% 20boolean% 29
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top