[java] 자바 : 문자열과 ByteBuffer 간 변환 및 관련 문제

소켓 연결에 Java NIO를 사용하고 있으며 프로토콜은 텍스트 기반이므로 SocketChannel에 쓰기 전에 문자열을 ByteBuffer로 변환하고 들어오는 ByteBuffer를 다시 문자열로 변환 할 수 있어야합니다. 현재 다음 코드를 사용하고 있습니다.

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

이것은 대부분의 경우 작동하지만 이것이이 전환의 각 방향을 수행하는 데 선호되는 (또는 가장 간단한) 방법인지 또는 시도 할 다른 방법이 있는지 질문합니다. 때때로, 겉보기에 무작위로, 호출 encode()decode()던져 것입니다
java.lang.IllegalStateException: Current state = FLUSHED, new state = CODING_END나는 새의 ByteBuffer 객체에게 변환이 수행 될 때마다 사용하고 경우에도 예외 또는 유사한. 이러한 방법을 동기화해야합니까? 문자열과 ByteBuffer 사이를 변환하는 더 좋은 방법이 있습니까? 감사!



답변

아웃 확인 CharsetEncoderCharsetDecoderAPI 설명 – 당신은 따라야 메소드 호출의 특정 순서를 이 문제를 방지 할 수 있습니다. 예를 들면 다음과 CharsetEncoder같습니다.

  1. reset이전에 사용하지 않은 경우 방법을 통해 인코더를 재설정하십시오 .
  2. encode추가 입력을 사용할 수있는 한 메서드를 0 번 이상 호출하고 falseendOfInput 인수를 전달 하고 입력 버퍼를 채우고 호출 사이에 출력 버퍼를 비 웁니다.
  3. encode마지막으로 메소드를 호출하고 trueendOfInput 인수를 전달하십시오. 그리고
  4. flush인코더가 내부 상태를 출력 버퍼로 플러시 할 수 있도록 메서드를 호출합니다 .

그건 그렇고, 내 동료 중 일부는 ASCII 만 사용한다는 지식으로 각 문자를 바이트로 직접 변환하지만 NIO에 사용하는 것과 동일한 접근 방식입니다.


답변

상황이 바뀌지 않는 한

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

일반적으로 buffer.hasArray ()는 사용 사례에 따라 항상 true 또는 false입니다. 실제로 어떤 상황에서도 실제로 작동하기를 원하지 않는 한 필요하지 않은 브랜치를 최적화하는 것이 안전합니다.


답변

Adamski의 답변은 좋은 것이며 일반 인코딩 방법을 사용할 때 인코딩 작업의 단계를 설명합니다 (입력 중 하나로 바이트 버퍼 사용).

그러나 문제의 메서드 (이 토론에서)는 encode- encode (CharBuffer in) 의 변형입니다 . 전체 인코딩 작업을 구현 하는 편리한 방법입니다. . (PS의 Java 문서 참조를 참조하십시오)

문서에 따라 인코딩 작업이 이미 진행중인 경우이 메서드를 호출하면 안됩니다. (다중 스레드 환경에서 정적 인코더 / 디코더 사용).

개인적으로 나는 커버 아래의 모든 단계를 수행하여 부담을 덜어주기 때문에 (보다 일반적인 인코딩 / 디코딩 방법보다) 편리한 방법 을 사용하는 것을 좋아합니다 .

ZenBlender와 Adamski는 이미 의견에서이를 안전하게 수행 할 수있는 여러 가지 옵션을 제안했습니다. 여기에 모두 나열 :

  • 각 작업에 필요할 때 새 인코더 / 디코더 개체를 만듭니다 (많은 개체로 이어질 수 있으므로 효율적이지 않음). 또는,
  • ThreadLocal을 사용하여 각 작업에 대해 새 인코더 / 디코더를 만들지 않도록합니다. 또는,
  • 전체 인코딩 / 디코딩 작업을 동기화합니다 (프로그램에 대해 일부 동시성을 희생하지 않는 한 선호되지 않을 수 있음)

추신

자바 문서 참조 :

  1. 인코딩 (편의) 방법 : http://docs.oracle.com/javase/6/docs/api/java/nio/charset/CharsetEncoder.html#encode%28java.nio.CharBuffer%29
  2. 일반 인코딩 방법 : http://docs.oracle.com/javase/6/docs/api/java/nio/charset/CharsetEncoder.html#encode%28java.nio.CharBuffer,%20java.nio.ByteBuffer,%20boolean% 29


답변