Program Tip

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

programtip 2020. 10. 10. 10:54
반응형

자바 : 문자열과 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의 답변은 좋은 답변이며 일반 인코딩 방법을 사용할 때 인코딩 작업의 단계를 설명합니다 (입력 중 하나로 바이트 버퍼 사용).

However, the method in question (in this discussion) is a variant of encode - encode(CharBuffer in). This is a convenience method that implements the entire encoding operation. (Please see java docs reference in P.S.)

As per the docs, This method should therefore not be invoked if an encoding operation is already in progress (which is what is happening in ZenBlender's code -- using static encoder/decoder in a multi threaded environment).

Personally, I like to use convenience methods (over the more general encode/decode methods) as they take away the burden by performing all the steps under the covers.

ZenBlender and Adamski have already suggested multiple ways options to safely do this in their comments. Listing them all here:

  • Create a new encoder/decoder object when needed for each operation (not efficient as it could lead to a large number of objects). OR,
  • Use a ThreadLocal to avoid creating new encoder/decoder for each operation. OR,
  • Synchronize the entire encoding/decoding operation (this might not be preferred unless sacrificing some concurrency is ok for your program)

P.S.

java docs references:

  1. Encode (convenience) method: http://docs.oracle.com/javase/6/docs/api/java/nio/charset/CharsetEncoder.html#encode%28java.nio.CharBuffer%29
  2. General encode method: http://docs.oracle.com/javase/6/docs/api/java/nio/charset/CharsetEncoder.html#encode%28java.nio.CharBuffer,%20java.nio.ByteBuffer,%20boolean%29

참고URL : https://stackoverflow.com/questions/1252468/java-converting-string-to-and-from-bytebuffer-and-associated-problems

반응형