UTF-8 байт [] в строку

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;    
}
skeryl
источник
17
Почему ты не можешь просто сделать это String fileString = new String(_bytes,"UTF-8");?
CoolBeans
1
Кроме того, вы можете использовать BufferedReader для чтения в массив символов.
Энди Томас,
@CoolBeans Я мог бы, если бы знал, что сделать это;) Спасибо.
скерил
В зависимости от размера файла, я не уверен, что загрузка целого byte[]в память и преобразование его через new String(_bytes,"UTF-8")(или даже с помощью кусочков +=в строке) является наиболее эффективным. Цепочки InputStreams и Readers могут работать лучше, особенно для больших файлов.
Бруно

Ответы:

498

Посмотрите на конструктор для String

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

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

String str = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
Джейсон Николс
источник
13
Или гуавы в Charsets.UTF_8 , если вы на JDK старше 1,7
siledh
6
Используйте Charsets.UTF_8 от Guava, если вы используете Android API ниже 19
Бен Клэйтон,
И если checkstyle говорит: «Нелегальное создание экземпляров: создание 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) устарела.
Аунг Мьят Хейн
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) конструктор для этого. Смотрите эту ссылку для деталей. РЕДАКТИРОВАТЬ Вы также должны учитывать кодировку по умолчанию вашей Plateform согласно документации Java:

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

Гета
источник
1
И если ваши байты не входят в кодировку платформы по умолчанию, вы можете использовать версию с вторым Charsetаргументом, чтобы убедиться в правильности преобразования.
Майк Дэниелс
1
@MikeDaniels Действительно, я не хотел включать все детали. Только что отредактировал мой ответ
GETah
2

Вы можете использовать методы, описанные в этом вопросе (особенно если вы начинаете с InputStream): чтение / преобразование InputStream в строку

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

Bruno
источник
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();
}
scottt
источник
Код отредактирован, чтобы сделать по умолчанию utf-8, чтобы соответствовать вопросу OP.
Скотт
1

String имеет конструктор, который принимает byte [] и charsetname в качестве параметров :)

soulcheck
источник
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();    
}
bragboy
источник
8
мой дорогой лорд. String str = new String(byte[])все будет хорошо.
Зенг
3
Это повышает эффективность, но не правильно декодирует данные utf8.
Тед Хопп
0

Почему бы не получить то, что вы ищете с самого начала, и прочитать строку из файла вместо массива байтов? Что-то вроде:

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

затем прочитайте LineIn, пока это не будет сделано.

digitaljoel
источник
Иногда полезно сохранить оригинальные разделители строк. ОП может хотеть этого.
Бруно
0

Я использую этот способ

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

Анатолий Пелепец
источник
1
Это не определяет набор символов, поэтому вы получаете набор символов по умолчанию для платформы, который вполне может быть не UTF-8.
greg-449