Pergunta

Estou usando o Java Nio para minhas conexões de soquete, e meu protocolo é baseado em texto, por isso preciso ser capaz de converter strings em bytesbuffers antes de escrevê -los no SocketchAnnel e converter os bytebuffers de entrada em cordas. Atualmente, estou 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;
}

Isso funciona na maioria das vezes, mas questiono se essa é a maneira preferida (ou mais simples) de fazer cada direção dessa conversão ou se há outra maneira de tentar. Ocasionalmente, e aparentemente aleatoriamente, chamadas para encode() e decode() vai jogar umjava.lang.IllegalStateException: Current state = FLUSHED, new state = CODING_END Exceção, ou similar, mesmo se eu estiver usando um novo objeto de bytebuffer cada vez que uma conversão é feita. Preciso sincronizar esses métodos? Alguma maneira melhor de converter entre cordas e bytesbuffers? Obrigado!

Foi útil?

Solução

Confira o CharsetEncoder e CharsetDecoder Descrições da API - você deve seguir um Sequência específica de chamadas de método para evitar esse problema. Por exemplo, para CharsetEncoder:

  1. Redefinir o codificador através do reset método, a menos que não tenha sido usado antes;
  2. Invocar o encode Método zero ou mais vezes, desde que a entrada adicional possa estar disponível, passando false para o argumento do endofinput e preenchendo o buffer de entrada e a liberação do buffer de saída entre as invocações;
  3. Invocar o encode Método uma última vez, passando true para o argumento do endofinput; e depois
  4. Invocar o flush Método para que o codificador possa liberar qualquer estado interno no buffer de saída.

A propósito, essa é a mesma abordagem que estou usando para o NIO, embora alguns de meus colegas estejam convertendo cada char diretamente em um byte, com conhecimento que eles estão usando apenas ASCII, que eu posso imaginar provavelmente é mais rápido.

Outras dicas

A menos que as coisas tenham mudado, você está melhor com

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);
}

Normalmente, o buffer.hasarray () será sempre verdadeiro ou sempre falso, dependendo do seu caso de uso. Na prática, a menos que você realmente queira funcionar em qualquer circunstância, é seguro otimizar o ramo que você não precisa.

A resposta de Adamski é boa e descreve as etapas em uma operação de codificação ao usar o método Geral Encodes (que pega um buffer de byte como uma das entradas)

No entanto, o método em questão (nesta discussão) é uma variante da codificação - codificar (charbuffer in). Isto é um Método de conveniência que implementa toda a operação de codificação. (Por favor, consulte a referência do Java Docs no PS)

De acordo com os documentos, Portanto, este método não deve ser invocado se uma operação de codificação já estiver em andamento (que é o que está acontecendo no código do Zenblender - usando o codificador/decodificador estático em um ambiente com vários rosqueados).

Pessoalmente, eu gosto de usar conveniência Métodos (sobre os métodos mais gerais de codificação/decodificação) enquanto eles tiram o ônus executando todas as etapas sob as cobertas.

Zenblender e Adamski já sugeriram várias maneiras de fazer isso com segurança em seus comentários. Listando todos eles aqui:

  • Crie um novo objeto de codificador/decodificador quando necessário para cada operação (não eficiente, pois pode levar a um grande número de objetos). OU,
  • Use um ThreadLocal para evitar a criação de um novo codificador/decodificador para cada operação. OU,
  • Sincronizar toda a operação de codificação/decodificação (isso pode não ser preferido, a menos que sacrificar alguma simultaneidade seja bom para o seu programa)

Ps

Java Docs Referências:

  1. Método de codificação (conveniência): http://docs.oracle.com/javase/6/docs/api/java/nio/charset/chartesencoder.html#encode%28java.nio.charbuffer%29
  2. Método de codificação geral: http://docs.oracle.com/javase/6/docs/api/java/nio/charset/chartesencoder.html#encode%28java.nio.charbuffer ,%20java.nio.byteBuffer ,%20BoOLean%29
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top