Перетворення байтового масиву в String (Java)


85

Я пишу веб-програму в Google App Engine. Це дозволяє людям в основному редагувати html-код, який зберігається як .htmlфайл у магазині.

Я використовую fetchData, щоб повернути a byte[]усіх символів у файлі. Я намагаюся надрукувати на html, щоб користувач міг редагувати html-код. Все працює чудово!

Ось моя єдина проблема зараз:

Байтовий масив має деякі проблеми при перетворенні назад у рядок. Розумні цитати та пара символів виходять виглядаючими у стилі фанк. (символи? чи японські символи тощо) Зокрема, це кілька байтів, які я бачу, що мають негативні значення, що спричиняє проблему.

Розумні лапки повертаються як у байтовому масиві, так -108і -109в нього. Чому це і як я можу декодувати від’ємні байти, щоб показати правильне кодування символів?



Привіт, я знаю, що це справді стара публікація, але я стикаюся з подібними проблемами. Я роблю проксі-сервер для ssl. Проблема, з якою я стикаюся, така ж, як і ваша. Я слухаю сокет і отримую дані, InputStreamа потім в byte[]. Тепер, коли я намагаюся перетворити byte[]рядок у рядок (мені потрібно використовувати тіло відповіді для атак), я отримую справді кумедні символи, сповнені розумних лапок і знаків запитання, а що ні. Я вважаю , що ваша проблема в тому ж , як у мене , як ми обидва маємо справу з htmlв byte[]. Чи можете ви, будь ласка, пораду?
Парул С

До речі, я пішов настільки, щоб знайти кодування своєї системи за допомогою Sytem.properties і виявив, що це "Cp1252". Зараз я використовував, String str=new String(buffer, "Cp1252");але ніякої допомоги.
Parul S

Відповіді:


141

Байтовий масив містить символи у спеціальному кодуванні (яке ви повинні знати). Спосіб перетворення його в рядок:

String decoded = new String(bytes, "UTF-8");  // example for one encoding type

До речі - необроблені байти можуть виглядати як від’ємні десяткові знаки лише тому, що тип даних Java byteпідписаний, він охоплює діапазон від -128 до 127.


-109 = 0x93: Control Code "Set Transmit State"

Значення (-109) є недрукованим керуючим символом в UNICODE. Отже, UTF-8 не є правильним кодуванням для цього потоку символів.

0x93у "Windows-1252" - це "розумна пропозиція", яку ви шукаєте, тому ім'я Java у цьому кодуванні "Cp1252". Наступний рядок містить тестовий код:

System.out.println(new String(new byte[]{-109}, "Cp1252")); 

5
Я спробував використовувати UTF-8, і він все одно вийшов як? Як так, що це не знаходження відображення цих негативних значень?
Джош,

0x93 є допустимим байтом продовження в UTF-8, однак - наявність цього байта виключає його бути UTF-8, лише якщо він не приходить після байта з першими двома встановленими бітами.
Нік Джонсон,

1
@Josh Andreas пояснює, чому - тому що byteтип даних Java підписаний. «Від’ємні» значення - це лише байти з найбільш значущим набором байт. Він також пояснює, який найбільш вірогідний набір символів, який ви повинні використовувати, - Windows-1252. Ви повинні знати, який набір символів використовувати з контексту або домовленості, не потребуючи припущення.
Нік Джонсон,

25

Java 7 і вище

Ви також можете передати бажане кодування Stringконструктору як Charsetконстанту з StandardCharsets . Це може бути безпечніше, ніж передача кодування як String, як пропонується в інших відповідях.

Наприклад, для кодування UTF-8

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

1
Це повторення відповіді з 2011 року. -1
james.garriss

2
@ james.garriss Я не думаю, що це так, оскільки я просто згадую новий конструктор, введений в Java 7, що дозволяє передавати кодування як константу, що, на мій погляд, приємніше і безпечніше, ніж попередній api згадані в попередніх відповідях, де кодування передавалось як рядок, якщо взагалі.
davnicwil


5
public class Main {

    /**
     * Example method for converting a byte to a String.
     */
    public void convertByteToString() {

        byte b = 65;

        //Using the static toString method of the Byte class
        System.out.println(Byte.toString(b));

        //Using simple concatenation with an empty String
        System.out.println(b + "");

        //Creating a byte array and passing it to the String constructor
        System.out.println(new String(new byte[] {b}));

    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new Main().convertByteToString();
    }
}

Вихідні дані

65
65
A

5
public static String readFile(String fn)   throws IOException 
{
    File f = new File(fn);

    byte[] buffer = new byte[(int)f.length()];
    FileInputStream is = new FileInputStream(fn);
    is.read(buffer);
    is.close();

    return  new String(buffer, "UTF-8"); // use desired encoding
}

3
Цей код витікає з ресурсу, якщо readвиникає виняток.
Raedwald,

4

я пропоную Arrays.toString(byte_array);

Це залежить від вашої мети. Наприклад, я хотів зберегти байтовий масив точно так само, як формат, який ви можете бачити під час налагодження, приблизно такий: [1, 2, 3]Якщо ви хочете зберегти саме те саме значення без перетворення байтів у формат символів, Arrays.toString (byte_array)робить це,. Але якщо ви хочете зберегти символи замість байтів, вам слід використовувати String s = new String(byte_array). У цьому випадку sдорівнює еквіваленту за [1, 2, 3]форматом символу.


Чи можете ви дати більше інформації про те, чому ви це пропонуєте? (Це вирішить проблему? Ви можете сказати, чому це вирішує?) Дякую!
Дін Дж.

Це залежить від вашої мети. Наприклад, я хотів зберегти байтовий масив точно так само, як формат, який ви можете бачити під час налагодження, приблизно такий: [1, 2, 3] Якщо ви хочете зберегти саме те саме значення без перетворення байтів у формат символів, Arrays.toString (byte_array) робить це ,. Але якщо ви хочете зберегти символи замість байтів, вам слід використовувати String s = new String (byte_array). У цьому випадку s дорівнює еквіваленту [1, 2, 3] у форматі символу.
Допитувач

@sas, вам слід додати цю інформацію до самої вашої відповіді (шляхом її редагування), а не як коментар. Як правило, щодо SO завжди слід пам’ятати, що коментарі в будь-який момент можуть бути видалені - справді важлива інформація повинна міститися у самій відповіді.
Jeen Broekstra

3

Попередня відповідь від Andreas_D - це добре. Я просто хочу додати, що де б ви не відображали вихідні дані, там буде кодування шрифтів і символів, і воно може не підтримувати деякі символи.

Щоб з’ясувати, чи є проблема Java чи ваш дисплей, зробіть наступне:

    for(int i=0;i<str.length();i++) {
        char ch = str.charAt(i);
        System.out.println(i+" : "+ch+" "+Integer.toHexString(ch)+((ch=='\ufffd') ? " Unknown character" : ""));
    }

Java буде зіставляти будь-які символи, які він не може зрозуміти, в 0xfffd офіційний символ для невідомих символів. Якщо ви бачите "?" у вихідному файлі, але він не відображається на 0xfffd, проблема полягає у вашому дисплеї або кодуванні, а не в Java.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.