UTF-8 байт [] до String


243

Припустимо, я щойно використав a BufferedInputStreamдля читання байтів текстового файлу, закодованого UTF-8, у байтовий масив. Я знаю, що я можу використовувати наступну процедуру для перетворення байтів у рядок, але чи є більш ефективний / розумніший спосіб зробити це, ніж просто ітерація через байти та перетворення кожного з них?

public String openFileToString(byte[] _bytes)
{
    String file_string = "";

    for(int i = 0; i < _bytes.length; i++)
    {
        file_string += (char)_bytes[i];
    }

    return file_string;    
}

17
Чому ви не можете просто зробити це String fileString = new String(_bytes,"UTF-8");?
CoolBeans

1
Крім того, ви можете використовувати BufferedReader для читання в масиві char.
Енді Томас


@CoolBeans я міг би, якби знав, що робити це;) Дякую.
skeryl

Залежно від розміру файлу, я не впевнений, що завантаження цілого byte[]в пам'ять і перетворення його за допомогою new String(_bytes,"UTF-8")(або навіть шматками +=в рядку) є найбільш ефективним. Зв'язування InputStreams та Readers може працювати краще, особливо на великих файлах.
Бруно

Відповіді:


498

Подивіться на конструктор для String

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

А якщо вам лінь, ви можете використовувати бібліотеку вводу- виводу Apache Commons для перетворення InputStream безпосередньо в String:

String str = IOUtils.toString(inputStream, StandardCharsets.UTF_8);

13
Або Шарви Гуави.UTF_8, якщо ви перебуваєте на JDK старше 1,7
siledh

6
Використовуйте Charsets Guava.UTF_8, якщо ви також користуєтесь API для Android нижче 19
Ben Clayton

І якщо в контрольному стилі сказано: "Незаконне інстанціонування: слід уникати миттєвості java.lang.String.", То що?
Аттіла Непарацький

1
Тут ви можете бачити java.nio.charset.Charset.availableCharsets()всі карти, а не лише їх у StandardCharsets. І якщо ви хочете скористатися якоюсь іншою схемою, і все ще хочете не допустити, щоб конструктор String не кидав, UnsupportedEncodingExceptionви можете використовуватиjava.nio.charset.Charset.forName()
nyxz

2
IOUtils.toString (inputStream, StandardCharsets.UTF_8) зараз застарілий.
Aung Myat Hein

41

Клас Java String має вбудований конструктор для перетворення байтового масиву в рядок.

byte[] byteArray = new byte[] {87, 79, 87, 46, 46, 46};

String value = new String(byteArray, "UTF-8");

9

Для перетворення даних utf-8 ви не можете припустити відповідність 1-1 між байтами та символами. Спробуйте це:

String file_string = new String(bytes, "UTF-8");

(Ба, я бачу, я маю можливість повільно натиснути кнопку "Опублікувати свою відповідь".)

Щоб прочитати весь файл у вигляді рядка, зробіть щось подібне:

public String openFileToString(String fileName) throws IOException
{
    InputStream is = new BufferedInputStream(new FileInputStream(fileName));

    try {
        InputStreamReader rdr = new InputStreamReader(is, "UTF-8");
        StringBuilder contents = new StringBuilder();
        char[] buff = new char[4096];
        int len = rdr.read(buff);
        while (len >= 0) {
            contents.append(buff, 0, len);
        }
        return buff.toString();
    } finally {
        try {
            is.close();
        } catch (Exception e) {
            // log error in closing the file
        }
    }
}

4

Ви можете використовувати String(byte[] bytes) конструктор для цього. Детальну інформацію див. За цим посиланням . РЕДАКТУВАННЯ Вам також потрібно врахувати схему за замовчуванням вашої форми, згідно з документом java:

Конструює новий рядок, розшифровуючи вказаний масив байтів за допомогою схеми за замовчуванням платформи. Довжина нового рядка - це функція діаграми, а значить, може бути не дорівнює довжині байтового масиву. Поведінка цього конструктора, коли задані байти недійсні в діаграмі за замовчуванням, не визначено. Клас CharsetDecoder слід використовувати, коли потрібно більше контролю над процесом декодування.


1
І якщо ваші байти не входять до схеми за замовчуванням платформи, ви можете скористатися версією, у якій є другий Charsetаргумент, щоб переконатися в правильності перетворення.
Майк Даніельс

1
@MikeDaniels Дійсно, я не хотів включати всі деталі. Щойно відредагував мою відповідь
GETah

2

Ви можете використовувати методи, описані в цьому запитанні (тим більше, що ви починаєте з InputStream): читання / перетворення InputStream у рядок

Зокрема, якщо ви не хочете , щоб покладатися на зовнішні бібліотеки, ви можете спробувати цей відповідь , який читає InputStreamчерез InputStreamReaderв char[]буфер і приєднує його в StringBuilder.


2

Знаючи, що ви маєте справу з байтовим масивом UTF-8, вам обов'язково захочеться використовувати конструктор String, який приймає ім'я шаблона . В іншому випадку ви можете залишити себе відкритими для деяких вразливих місць безпеки, що кодують кодування. Зауважте, що це кидає, з UnsupportedEncodingExceptionяким вам доведеться впоратися. Щось на зразок цього:

public String openFileToString(String fileName) {
    String file_string;
    try {
        file_string = new String(_bytes, "UTF-8");
    } catch (UnsupportedEncodingException e) {
        // this should never happen because "UTF-8" is hard-coded.
        throw new IllegalStateException(e);
    }
    return file_string;
}

2

Ось спрощена функція, яка буде читати в байтах і створювати рядок. Це передбачає, що ви, мабуть, уже знаєте, у чому кодуванні знаходиться файл (та в іншому випадку за замовчуванням).

static final int BUFF_SIZE = 2048;
static final String DEFAULT_ENCODING = "utf-8";

public static String readFileToString(String filePath, String encoding) throws IOException {

    if (encoding == null || encoding.length() == 0)
        encoding = DEFAULT_ENCODING;

    StringBuffer content = new StringBuffer();

    FileInputStream fis = new FileInputStream(new File(filePath));
    byte[] buffer = new byte[BUFF_SIZE];

    int bytesRead = 0;
    while ((bytesRead = fis.read(buffer)) != -1)
        content.append(new String(buffer, 0, bytesRead, encoding));

    fis.close();        
    return content.toString();
}

Код відредагований, щоб за замовчуванням було utf-8, щоб відповідати питанню ОП.
Скоттт

1

У String є конструктор, який бере параметри байтів [] та charsetname :)


0

Це також включає ітерацію, але це набагато краще, ніж об'єднання рядків, оскільки вони дуже дорогі.

public String openFileToString(String fileName)
{
    StringBuilder s = new StringBuilder(_bytes.length);

    for(int i = 0; i < _bytes.length; i++)
    {
        s.append((char)_bytes[i]);
    }

    return s.toString();    
}

8
мій шановний пане. String str = new String(byte[])зробить просто чудово.
zengr

3
Це підвищує ефективність, але не декодує utf8 даних належним чином.
Тед Хопп

0

Чому б не отримати те, що ви шукаєте, з get go і прочитати рядок з файлу замість масиву байтів? Щось на зразок:

BufferedReader in = new BufferedReader(new InputStreamReader( new FileInputStream( "foo.txt"), Charset.forName( "UTF-8"));

потім читайте Line з, поки це не буде зроблено.


Іноді корисно тримати оригінальні роздільники ліній. ОП може цього захотіти.
Бруно

0

Я використовую цей спосіб

String strIn = new String(_bytes, 0, numBytes);


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