Java ByteBuffer에서 문자열로


122

이런 식으로 ByteBuffer를 String으로 변환하는 올바른 접근 방식입니까?

String k = "abcd";
ByteBuffer b = ByteBuffer.wrap(k.getBytes());
String v = new String(b.array());

if(k.equals(v))
    System.out.println("it worked");
else
    System.out.println("did not work");

내가 묻는 이유는 이것이 너무 단순 해 보이지만 Java 와 같은 다른 접근 방식 : ByteBuffer와의 문자열 변환 및 관련 문제 가 더 복잡해 보이기 때문입니다.


3
글쎄, 해봤 어?
tckmn 2013 년

6
네, 그랬습니다. 하지만 같은 더 복잡한 다른 구현, 본 stackoverflow.com/questions/1252468/...
vikky.rk

1
@Doorknob et. al. 그는 인코딩이 누락되었고 그의 예제 (구문이 수정되었을 때)는 작동하지만 그의 방법은 여전히 ​​옳지 않습니다.
Gus

답변:


83

편집 (2018) : @xinyongCheng의 편집 된 형제 답변은 더 간단한 접근 방식이며 허용되는 답변이어야합니다.

바이트가 플랫폼의 기본 문자 세트에 있음을 알고 있다면 접근 방식이 합리적입니다. 귀하의 예에서 이것은 k.getBytes()플랫폼의 기본 문자 집합의 바이트를 반환 하기 때문에 사실 입니다.

더 자주 인코딩을 지정하는 것이 좋습니다. 그러나 연결 한 질문보다 더 간단한 방법이 있습니다. String API는 특정 인코딩에서 String과 byte [] 배열 사이를 변환하는 메소드를 제공합니다. 이러한 메서드는 "디코딩 [인코딩] 프로세스에 대한 더 많은 제어가 필요한 경우" CharsetEncoder / CharsetDecoder를 사용하는 것이 좋습니다 .

특정 인코딩의 문자열에서 바이트를 가져 오려면 형제 getBytes () 메서드를 사용할 수 있습니다.

byte[] bytes = k.getBytes( StandardCharsets.UTF_8 );

특정 인코딩의 바이트를 String에 넣으려면 다른 String 생성자를 사용할 수 있습니다.

String v = new String( bytes, StandardCharsets.UTF_8 );

참고 ByteBuffer.array()옵션 작업입니다. 배열로 ByteBuffer를 구성한 경우 해당 배열을 직접 사용할 수 있습니다. 그렇지 않으면 안전을 원하면을 사용 ByteBuffer.get(byte[] dst, int offset, int length)하여 버퍼에서 바이트 배열로 바이트를 가져옵니다.


과의 ByteBuffer.get기능, 입력 바이트의 배열, 내가 그것을 어떻게 얻을 수 다시입니까? 다시 k.getbytes라고 말하는 것은 이치에 맞지 않습니까?
William Kinaan

@WilliamKinaan-당신은 당신이 공급 한 byte []를 가지고 있습니다 ByteBuffer.get(byte[] dst, int offset, int length). String () 생성자`String (byte [] bytes, int offset, int length, Charset charset)을 사용하여 String을 만들 수 있습니다. 두 호출에 대해 동일한 오프셋 및 길이 값을 사용할 수 있습니다.
Andy Thomas

java.nio.ByteBuffer에는 k.getBytes () 메소드가 없습니다 (사용중인 버전이 아닐 수 있음). 그래서 byte []를 반환하는 k.array () 메서드를 사용했습니다.
마두 프라 딥

@MaduraPradeep-질문의 예제 코드와이 답변에서 kByteBuffer가 아닌 문자열입니다.
Andy Thomas

UTF-8은 바이트를 문자열로 또는 그 반대로 변환하는 데 최적의 문자 집합이 아닐 수 있습니다. 문자에 대한 바이트의 일대일 매핑은 ISO-8859-1을 더 잘 사용하려면 stackoverflow.com/questions/9098022/…를
asmaier

103

Andy Thomas가 언급 한 문제없이 a ByteBuffer를 a 로 디코딩하는 더 간단한 방법이 있습니다 String.

String s = StandardCharsets.UTF_8.decode(byteBuffer).toString();

2
UTF-8은 바이트를 문자열로 또는 그 반대로 변환하는 데 최적의 문자 집합이 아닐 수 있습니다. 문자에 대한 바이트의 일대일 매핑은 ISO-8859-1을 더 잘 사용하려면 stackoverflow.com/questions/9098022/…를 참조하십시오 .
asmaier

또한 문자열이 실제로 필요 하지 않으며 CharBuffer decode()반환 값은 CharSequence(같은 String)이므로 추가 사본을 피하고 직접 사용할 수 있습니다.
David Ehrmann

15

이 시도:

new String(bytebuffer.array(), "ASCII");

NB. 인코딩을 모르면 바이트 배열을 문자열로 올바르게 변환 할 수 없습니다.

이게 도움이 되길 바란다


10
UTF-8은 아마도 ASCII보다 더 나은 기본 추측일까요?
Gus

3
플랫폼의 기본 문자 집합을 사용하는 k.getBytes ()를 OP에서 사용하므로 둘 다 지정해서는 안됩니다.
Andy Thomas

7
모든 버퍼가 배열로 지원되는 것은 아니므 .array()로 예외가 발생할 수 있습니다.
Dzmitry Lazerka

모든 바이트 버퍼가 .array()메서드를 지원하는 것은 아닙니다 .
ScalaWilliam

3
꼼꼼한! 당신이 사용하는 경우 array(), 당신은 해야한다 또한 사용하는 arrayOffset()배열의 올바른 위치에서 시작합니다! 보통 arrayOffset ()이 0이기 때문에 이것은 미묘한 함정입니다. 그러나 그렇지 않은 드문 경우에는 고려하지 않으면 찾기 어려운 버그가 발생합니다.
올리버

13

ByteBuffer.array ()가 항상 작동한다고 가정하는 것은 안전하지 않습니다.

byte[] bytes;
if(buffer.hasArray()) {
    bytes = buffer.array();
} else {
    bytes = new byte[buffer.remaining()];
    buffer.get(bytes);
}
String v = new String(bytes, charset);

일반적으로 buffer.hasArray ()는 사용 사례에 따라 항상 true 또는 false입니다. 실제로 어떤 상황에서도 실제로 작동하기를 원하지 않는 한 필요하지 않은 브랜치를 최적화하는 것이 안전합니다. 그러나 나머지 답변은 ByteBuffer.allocateDirect ()를 통해 생성 된 ByteBuffer에서 작동하지 않을 수 있습니다.


ByteBuffer.wrap(bytes, offset, size)공장 .array()을 통해 버퍼가 생성 되면 전체 bytes배열 이 반환 됩니다. xinyong Cheng이 제안한 양식을 더 잘 사용하십시오
Lev Kuznetsov

Charset의 .decode ()가 더 나은 솔루션이라고 동의했습니다. 내 대답의 맥락이 유용한 정보라고 생각하지만 지금은 훨씬 적습니다.
Fuwjax

2
꼼꼼한! 당신이 사용하는 경우 array(), 당신은 해야한다 또한 사용하는 arrayOffset()배열의 올바른 위치에서 시작합니다! 보통 arrayOffset ()이 0이기 때문에 이것은 미묘한 함정입니다. 그러나 그렇지 않은 드문 경우에는 고려하지 않으면 찾기 어려운 버그가 발생합니다.
올리버

8

단순히 호출에 대한 답변 array()은 정확하지 않습니다. 버퍼가 부분적으로 사용되었거나 배열의 일부를 참조하는 경우 ( ByteBuffer.wrap처음부터는 아니지만 지정된 오프셋에서 배열이 가능함), 우리는 다음 사항을 고려해야합니다. 우리 계산에서. 이것은 모든 경우에 버퍼에 대해 작동하는 일반적인 솔루션입니다 (인코딩을 다루지 않음).

if (myByteBuffer.hasArray()) {
    return new String(myByteBuffer.array(),
        myByteBuffer.arrayOffset() + myByteBuffer.position(),
        myByteBuffer.remaining());
} else {
    final byte[] b = new byte[myByteBuffer.remaining()];
    myByteBuffer.duplicate().get(b);
    return new String(b);
}

인코딩과 관련된 문제는 Andy Thomas의 답변을 참조하십시오.


2

이 질문의 근원은 바이트를 문자열로 디코딩하는 방법입니다.

이것은 JAVA NIO CharSet으로 수행 할 수 있습니다.

public final CharBuffer decode(ByteBuffer bb)

FileChannel channel = FileChannel.open(
  Paths.get("files/text-latin1.txt", StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer);

CharSet latin1 = StandardCharsets.ISO_8859_1;
CharBuffer latin1Buffer = latin1.decode(buffer);

String result = new String(latin1Buffer.array());
  • 먼저 채널을 만들고 버퍼에서 읽습니다.
  • 그런 다음 디코딩 메서드는 Latin1 버퍼를 char 버퍼로 디코딩합니다.
  • 그런 다음 결과를 예를 들어 String에 넣을 수 있습니다.

코드가 latin1에서 utf8로 디코딩되지 않습니다. 코드가 정확하지만 CharBuffer utf8Buffer를 호출하는 것은 인코딩이 없기 때문에 다소 오해의 소지가 있습니다.
Björn Lindqvist

1

인코딩 문제를 제외하고 링크 된 더 복잡한 코드 중 일부는 단순히 모든 바이트를 인코딩하는 것이 아니라 해당 ByteBuffer의 "활성"부분 (예 : 위치 및 제한 사용)을 가져 오는 문제로 이어진다는 점에 유의하십시오. 전체 백업 배열에서 (이 답변의 많은 예가 그렇듯이).


1

문자열을 ByteBuffer로 변환 한 다음 Java를 사용하여 ByteBuffer에서 다시 문자열로 변환합니다.

import java.nio.charset.Charset;
import java.nio.*;

String babel = "obufscate thdé alphebat and yolo!!";
System.out.println(babel);
//Convert string to ByteBuffer:
ByteBuffer babb = Charset.forName("UTF-8").encode(babel);
try{
    //Convert ByteBuffer to String
    System.out.println(new String(babb.array(), "UTF-8"));
}
catch(Exception e){
    e.printStackTrace();
}

인쇄 된 베어 문자열을 먼저 인쇄 한 다음 array ()로 캐스팅 된 ByteBuffer를 인쇄합니다.

obufscate thdé alphebat and yolo!!
obufscate thdé alphebat and yolo!!

또한 이것은 나에게 도움이되었고, 문자열을 원시 바이트로 줄이면 무슨 일이 일어나고 있는지 검사하는 데 도움이 될 수 있습니다.

String text = "こんにちは";
//convert utf8 text to a byte array
byte[] array = text.getBytes("UTF-8");
//convert the byte array back to a string as UTF-8
String s = new String(array, Charset.forName("UTF-8"));
System.out.println(s);
//forcing strings encoded as UTF-8 as an incorrect encoding like
//say ISO-8859-1 causes strange and undefined behavior
String sISO = new String(array, Charset.forName("ISO-8859-1"));
System.out.println(sISO);

UTF-8로 해석 된 다음 다시 ISO-8859-1로 해석 된 문자열을 인쇄합니다.

こんにちは
ããã«ã¡ã¯

0
private String convertFrom(String lines, String from, String to) {
    ByteBuffer bb = ByteBuffer.wrap(lines.getBytes());
    CharBuffer cb = Charset.forName(to).decode(bb);
    return new String(Charset.forName(from).encode(cb).array());
};
public Doit(){
    String concatenatedLines = convertFrom(concatenatedLines, "CP1252", "UTF-8");
};
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.