Преобразовать InputStream в String с кодировкой, указанной в данных потока - PullRequest
3 голосов
/ 20 мая 2010

Мой ввод - это InputStream, который содержит документ XML. Используемая в XML кодировка неизвестна и определяется в первой строке XML-документа. Из этого InputStream я хочу, чтобы весь документ был в строке.

Для этого я использую BufferedInputStream, чтобы отметить начало файла и начать чтение первой строки. Я читаю эту первую строку для получения кодировки, а затем использую InputStreamReader для генерации строки с правильной кодировкой.

Похоже, что это не лучший способ достижения этой цели, поскольку он вызывает ошибку OutOfMemory.

Есть идеи, как это сделать?

public static String streamToString(final InputStream is) {
    String result = null;

    if (is != null) {
        BufferedInputStream bis = new BufferedInputStream(is);
        bis.mark(Integer.MAX_VALUE);
        final StringBuilder stringBuilder = new StringBuilder();
        try {
            // stream reader that handle encoding
            final InputStreamReader readerForEncoding = new InputStreamReader(bis, "UTF-8");
            final BufferedReader bufferedReaderForEncoding = new BufferedReader(readerForEncoding);

            String encoding = extractEncodingFromStream(bufferedReaderForEncoding);
            if (encoding == null) {
                encoding = DEFAULT_ENCODING;
            }

            // stream reader that handle encoding
            bis.reset();
            final InputStreamReader readerForContent = new InputStreamReader(bis, encoding);
            final BufferedReader bufferedReaderForContent = new BufferedReader(readerForContent);

            String line = bufferedReaderForContent.readLine();
            while (line != null) {
                stringBuilder.append(line); 
                line  = bufferedReaderForContent.readLine();
            } 
            bufferedReaderForContent.close();
            bufferedReaderForEncoding.close();
        } catch (IOException e) { 
            // reset string builder
            stringBuilder.delete(0, stringBuilder.length());
        }  
        result = stringBuilder.toString();
    }else {
        result = null;
    }
    return result;
}

Ответы [ 2 ]

2 голосов
/ 20 мая 2010

Вызов mark(Integer.MAX_VALUE) вызывает OutOfMemoryError, так как он пытается выделить 2 ГБ памяти.

Это можно решить с помощью итеративного подхода.Установите отметку readLimit на разумное значение, скажем, 8K.В 99% случаев это будет работать, но в патологических случаях, например, 16K пробелов между атрибутами в объявлении, вам нужно будет повторить попытку.Таким образом, есть цикл, который пытается найти кодировку, но если он не находит ее в заданной области меток, он пытается снова, удваивая запрошенный размер метки readLimit.Чтобы продвинуть поток ввода выше предела метки, вы должны сами прочитать InputStream до предела метки в байтовый массив.Затем вы оборачиваете байтовый массив в ByteArrayInputStream и передаете его в конструктор InputStreamReader, назначенный для «readerForEncoding».

0 голосов
/ 08 января 2013

Вы можете использовать этот метод для преобразования входного потока в строку. это может помочь вам ...

private String convertStreamToString(InputStream input) throws Exception{
    BufferedReader reader = new BufferedReader(new InputStreamReader(input));
    StringBuilder sb = new StringBuilder();
    String line = null;

    while ((line = reader.readLine()) != null) {
        sb.append(line);
    }

    input.close();
    return sb.toString();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...