2013-06-27 12 views
78

Является ли это правильный подход, чтобы преобразовать ByteBuffer в строку таким образом,Java ByteBuffer в строку

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: Converting String to and from ByteBuffer and associated problems выглядит более сложным.

+2

Ну, вы попробовали? – Doorknob

+5

Да, я сделал, и он работает. Но я видел другие реализации, которые более сложны, например http://stackoverflow.com/questions/1252468/java-converting-string-to-and-from-bytebuffer-and-associated-problems –

+1

@Doorknob et. и др. Он пропускает кодировку, и его пример (когда синтаксис исправлен) будет работать, но его метод все еще не прав. – Gus

ответ

58

Ваш подход был бы разумно, если бы вы знали, что байты в кодировке по умолчанию платформы. В вашем примере это верно, потому что k.getBytes() возвращает байты в кодировке по умолчанию платформы.

Чаще всего вам нужно указать кодировку. Однако есть более простой способ сделать это, чем связанный с вами вопрос. API String предоставляет методы, которые преобразуются между массивом String и byte [] в конкретную кодировку. Эти методы предполагают использование CharsetEncoder/CharsetDecoder «когда требуется больше контроля процесса декодирования [кодирования]».

import java.nio.charset.Charset; 

Чтобы получить байты из строки в определенной кодировке, вы можете использовать одноуровневые GetBytes() метод:

byte[] bytes = k.getBytes(Charset.forName("UTF-8")); 

Чтобы поместить байты с определенной кодировкой в ​​строку, вы можете используйте другой конструктор Строки:

String v = new String(bytes, Charset.forName("UTF-8")); 

Обратите внимание, что ByteBuffer.array() является дополнительной операцией. Если вы построили ByteBuffer с массивом, вы можете использовать этот массив напрямую. В противном случае, если вы хотите быть в безопасности, используйте ByteBuffer.get(byte[] dst, int offset, int length), чтобы получить байты из буфера в массив байтов.

EDIT

В качестве побочного вопроса, в вышеприведенном примере кода вызова Charset.forName("UTF-8") должен работать для всех версий Java начиная с 1.4.

Если вы используете Java 7 или более поздней версии, вы можете использовать java.nio.charset.StandardCharsets.UTF_8. (Замечено по BenKirby в комментарии ниже.)

Если вы используете Guava, вы можете использовать вместо этого com.google.common.base.Charsets.UTF_8. (Замечание от космической камеры в комментарии ниже.)

+0

и в функции 'ByteBuffer.get', вход снова представляет собой массив байтов, как я могу его получить? не имеет смысла говорить снова k.getbytes, не так ли? –

+0

@WilliamKinaan - У вас есть байт [], который вы загрузили в 'ByteBuffer.get (byte [] dst, int offset, int length)'. Вы можете построить String из него с помощью конструктора String() 'String (byte [] bytes, int offset, int length, Charset charset). Вы можете использовать одни и те же значения смещения и длины для обоих вызовов. –

+0

В java.nio.ByteBuffer нет метода k.getBytes() (может быть, не используется в версии am). Поэтому я использовал метод k.array(), который вернет байт []. –

13

Попробуйте это:

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

NB. вы не можете правильно преобразовать массив байтов в строку, не зная его кодировки.

Я надеюсь, что это помогает

+9

UTF-8, вероятно, лучше по умолчанию, чем ASCII? – Gus

+3

Также не следует указывать, учитывая использование OP в k.getBytes(), которое использует кодировку платформы по умолчанию. –

+5

Не все буферы поддерживаются массивом, поэтому '.array()' может вызывать исключение. –

12

Просто хотел указать, небезопасно предположить, что 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() всегда будет истинным или ложным в зависимости от вашего варианта использования. На практике, если вы действительно не хотите, чтобы он работал ни при каких обстоятельствах, безопасно оптимизировать отрасль, которая вам не нужна. Но остальные ответы могут не работать с ByteBuffer, который был создан через ByteBuffer.allocateDirect().

+0

Если буфер создается через 'ByteBuffer.wrap (байты, смещение, размер) 'factory' .array() 'будет возвращать весь массив' bytes'. Лучше использовать форму xinyong Cheng, предложенную –

+0

.decode() на Charset - лучшее решение, согласованное. Я чувствую, что контекст моего ответа - полезная информация, но тем более сейчас. – Fuwjax

0

Уведомление (кроме проблемы с кодировкой), что некоторые из более сложных связанных кодов связаны с проблемой получения «активной» части рассматриваемого ByteBuffer (например, с использованием позиции и ограничения), а не просто кодирования все байты во всем массиве поддержки (как и многие из примеров в этих ответах).

3

Ответы, относящиеся к простому вызову 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); 
} 

Для проблем, связанных с кодированием, см ответ Энди Томаса.

1

Преобразование строки в ByteBuffer, то из ByteBuffer обратно в строку с помощью Java:

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

который печатает печатное голую строку первой, а затем 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:

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

Существует более простой подход для декодирования ByteBuffer в String без каких-либо проблем, упомянутых Энди Томас.

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

Помните, что UTF-8 может не быть оптимальной кодировкой для преобразования байтов в строки и наоборот. Для сопоставления байтов с символами 1 к 1 лучше использовать ISO-8859-1, см. Https://stackoverflow.com/questions/9098022/problems-converting-byte-array-to-string-and-back-to -байт-массив. – asmaier