Как мне прочитать / преобразовать InputStream в строку в Java?

4066

Если у вас есть java.io.InputStreamобъект, как вы должны обработать этот объект и создать String?


Предположим, у меня есть InputStreamтекст, содержащий текстовые данные, и я хочу преобразовать его в Stringфайл, поэтому, например, я могу записать его в файл журнала.

Какой самый простой способ взять InputStreamи преобразовать его в String?

public String convertStreamToString(InputStream is) {
    // ???
}
Джонни Водоворот
источник
36
Ответы на этот вопрос только работу , если вы хотите , чтобы прочитать содержимое потока , в полной мере (пока она не будет закрыта). Так как это не всегда предназначено (запросы http с сохраняющим соединение соединением не будут закрыты), эти вызовы метода блокируются (без предоставления вам содержимого).
f1sh
21
Вам необходимо знать и указывать кодировку символов для потока, иначе у вас будут ошибки кодировки символов, поскольку вы будете использовать случайно выбранную кодировку в зависимости от того, на какой машине / операционной системе / платформе или ее версии выполняется ваш код. То есть не используйте методы, которые зависят от кодировки платформы по умолчанию.
Кристофер Хаммарстрем
11
Просто чтобы повеселиться с моим собственным комментарием от 9 лет назад, в эти дни я использую Groovy "String s = new File (" SomeFile.txt "). Text", чтобы прочитать весь файл сразу, и это прекрасно работает. Я счастлив, что использую groovy для моего непроизводственного (скриптового) кода и - честно говоря, заставляю вас иметь дело с кодированием и очень длинными файлами, как это делает java, это действительно хорошая идея для производственного кода, так что он работает для своих целей, Groovy работает для быстрых сценариев, в которых java не очень хорош - просто используйте подходящий инструмент для работы, и все получится.
Билл К
Просто ByteArrayOutputStream outputBytes = new ByteArrayOutputStream(); for(byte[] b = new byte[512]; 0 < inputStream.read(b); outputBytes.write(b)); return new String(outputBytes.toByteArray(), StandardCharsets.UTF_8);
упрощаю
@BillK с Java 11, вы можете использовать то же, String s = Files.readString​(Path.of("SomeFile.txt"));что и язык, который никогда не будет поддерживать такие магические преобразования типов, как описанные вами.
Хольгер

Ответы:

2531

Хороший способ сделать это - использовать Apache Commons IOUtils для копирования InputStreamв StringWriter... что-то вроде

StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, encoding);
String theString = writer.toString();

или даже

// NB: does not close inputStream, you'll have to use try-with-resources for that
String theString = IOUtils.toString(inputStream, encoding); 

Кроме того, вы можете использовать, ByteArrayOutputStreamесли вы не хотите смешивать ваши потоки и пишущие

Гарри Лайм
источник
75
Для разработчиков Android кажется, что Android не поставляется с IOUtils от Apache. Так что вы можете рассмотреть возможность обращения к другим ответам.
Chris.Zou
47
На данный момент это невероятно старый вопрос (он был задан в 2008 году). Это стоит вашего времени, чтобы прочитать более современные ответы. Некоторые используют собственные вызовы из библиотеки Java 8.
Шадонинья,
36
Этот ответ сильно устарел, и его нужно пометить как таковой (к сожалению, это невозможно).
codepleb
7
IOUtils.toString () давно устарел. Этот ответ определенно больше не рекомендуется.
Рошан
7
затем отредактируйте его, чтобы объяснить, почему он устарел, чтобы помочь будущим читателям.
Жан-Франсуа Фабр
2487

Обобщая другие ответы, я нашел 11 основных способов сделать это (см. Ниже). И я написал несколько тестов производительности (см. Результаты ниже):

Способы преобразования InputStream в строку:

  1. Использование IOUtils.toString(Apache Utils)

    String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
  2. Использование CharStreams(Гуава)

    String result = CharStreams.toString(new InputStreamReader(
          inputStream, Charsets.UTF_8));
    
  3. Использование Scanner(JDK)

    Scanner s = new Scanner(inputStream).useDelimiter("\\A");
    String result = s.hasNext() ? s.next() : "";
    
  4. Использование Stream API (Java 8). Предупреждение . Это решение преобразует различные разрывы строк (например \r\n) в \n.

    String result = new BufferedReader(new InputStreamReader(inputStream))
      .lines().collect(Collectors.joining("\n"));
    
  5. Использование параллельного Stream API (Java 8). Предупреждение . Это решение преобразует различные разрывы строк (например \r\n) в \n.

    String result = new BufferedReader(new InputStreamReader(inputStream)).lines()
       .parallel().collect(Collectors.joining("\n"));
    
  6. Использование InputStreamReaderи StringBuilder(JDK)

    final int bufferSize = 1024;
    final char[] buffer = new char[bufferSize];
    final StringBuilder out = new StringBuilder();
    Reader in = new InputStreamReader(stream, StandardCharsets.UTF_8);
    int charsRead;
    while((charsRead = in.read(buffer, 0, buffer.length)) > 0) {
        out.append(buffer, 0, charsRead);
    }
    return out.toString();
    
  7. Использование StringWriterи IOUtils.copy(Apache Commons)

    StringWriter writer = new StringWriter();
    IOUtils.copy(inputStream, writer, "UTF-8");
    return writer.toString();
    
  8. Использование ByteArrayOutputStreamи inputStream.read(JDK)

    ByteArrayOutputStream result = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int length;
    while ((length = inputStream.read(buffer)) != -1) {
        result.write(buffer, 0, length);
    }
    // StandardCharsets.UTF_8.name() > JDK 7
    return result.toString("UTF-8");
    
  9. Использование BufferedReader(JDK). Предупреждение. Это решение преобразует различные разрывы строк (например \n\r) в line.separatorсистемное свойство (например, в Windows в «\ r \ n»).

    String newLine = System.getProperty("line.separator");
    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
    StringBuilder result = new StringBuilder();
    boolean flag = false;
    for (String line; (line = reader.readLine()) != null; ) {
        result.append(flag? newLine: "").append(line);
        flag = true;
    }
    return result.toString();
    
  10. Использование BufferedInputStreamи ByteArrayOutputStream(JDK)

    BufferedInputStream bis = new BufferedInputStream(inputStream);
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    int result = bis.read();
    while(result != -1) {
        buf.write((byte) result);
        result = bis.read();
    }
    // StandardCharsets.UTF_8.name() > JDK 7
    return buf.toString("UTF-8");
    
  11. Использование inputStream.read()и StringBuilder(JDK). Предупреждение : это решение имеет проблемы с Unicode, например с русским текстом (работает корректно только с текстом не-Unicode)

    int ch;
    StringBuilder sb = new StringBuilder();
    while((ch = inputStream.read()) != -1)
        sb.append((char)ch);
    reset();
    return sb.toString();
    

Предупреждение :

  1. Решения 4, 5 и 9 преобразуют различные разрывы строк в один.

  2. Решение 11 не может корректно работать с текстом Unicode

Тесты производительности

Тесты производительности для малых String(длина = 175), URL в github (режим = Среднее время, система = Linux, оценка 1343 является лучшим):

              Benchmark                         Mode  Cnt   Score   Error  Units
 8. ByteArrayOutputStream and read (JDK)        avgt   10   1,343 ± 0,028  us/op
 6. InputStreamReader and StringBuilder (JDK)   avgt   10   6,980 ± 0,404  us/op
10. BufferedInputStream, ByteArrayOutputStream  avgt   10   7,437 ± 0,735  us/op
11. InputStream.read() and StringBuilder (JDK)  avgt   10   8,977 ± 0,328  us/op
 7. StringWriter and IOUtils.copy (Apache)      avgt   10  10,613 ± 0,599  us/op
 1. IOUtils.toString (Apache Utils)             avgt   10  10,605 ± 0,527  us/op
 3. Scanner (JDK)                               avgt   10  12,083 ± 0,293  us/op
 2. CharStreams (guava)                         avgt   10  12,999 ± 0,514  us/op
 4. Stream Api (Java 8)                         avgt   10  15,811 ± 0,605  us/op
 9. BufferedReader (JDK)                        avgt   10  16,038 ± 0,711  us/op
 5. parallel Stream Api (Java 8)                avgt   10  21,544 ± 0,583  us/op

Тесты производительности для больших String(длина = 50100), URL в github (режим = Среднее время, система = Linux, оценка 200,715 является лучшей):

               Benchmark                        Mode  Cnt   Score        Error  Units
 8. ByteArrayOutputStream and read (JDK)        avgt   10   200,715 ±   18,103  us/op
 1. IOUtils.toString (Apache Utils)             avgt   10   300,019 ±    8,751  us/op
 6. InputStreamReader and StringBuilder (JDK)   avgt   10   347,616 ±  130,348  us/op
 7. StringWriter and IOUtils.copy (Apache)      avgt   10   352,791 ±  105,337  us/op
 2. CharStreams (guava)                         avgt   10   420,137 ±   59,877  us/op
 9. BufferedReader (JDK)                        avgt   10   632,028 ±   17,002  us/op
 5. parallel Stream Api (Java 8)                avgt   10   662,999 ±   46,199  us/op
 4. Stream Api (Java 8)                         avgt   10   701,269 ±   82,296  us/op
10. BufferedInputStream, ByteArrayOutputStream  avgt   10   740,837 ±    5,613  us/op
 3. Scanner (JDK)                               avgt   10   751,417 ±   62,026  us/op
11. InputStream.read() and StringBuilder (JDK)  avgt   10  2919,350 ± 1101,942  us/op

Графики (тесты производительности в зависимости от длины входного потока в системе Windows 7)
введите описание изображения здесь

Тест производительности (среднее время) в зависимости от длины входного потока в системе Windows 7:

 length  182    546     1092    3276    9828    29484   58968

 test8  0.38    0.938   1.868   4.448   13.412  36.459  72.708
 test4  2.362   3.609   5.573   12.769  40.74   81.415  159.864
 test5  3.881   5.075   6.904   14.123  50.258  129.937 166.162
 test9  2.237   3.493   5.422   11.977  45.98   89.336  177.39
 test6  1.261   2.12    4.38    10.698  31.821  86.106  186.636
 test7  1.601   2.391   3.646   8.367   38.196  110.221 211.016
 test1  1.529   2.381   3.527   8.411   40.551  105.16  212.573
 test3  3.035   3.934   8.606   20.858  61.571  118.744 235.428
 test2  3.136   6.238   10.508  33.48   43.532  118.044 239.481
 test10 1.593   4.736   7.527   20.557  59.856  162.907 323.147
 test11 3.913   11.506  23.26   68.644  207.591 600.444 1211.545
Вячеслав Веденин
источник
17
Когда вы пишете «краткий ответ», вы должны заметить, что некоторые решения автоматически преобразуют различные переводы строк (например \r\n), в \nкоторые в некоторых случаях могут быть нежелательны. Также было бы неплохо увидеть необходимую дополнительную память или, по крайней мере, давление выделения (по крайней мере, вы можете запустить JMH с -prof gc). Для действительно классного поста было бы замечательно увидеть графики (в зависимости от длины строки в пределах одного и того же размера ввода и в зависимости от размера ввода в пределах одной и той же длины строки).
Тагир Валеев
16
Upvoted; Самое смешное, что результаты превзошли все ожидания: нужно использовать стандартный синтаксический сахар JDK и / или Apache Commons.
Алексей Матюшкин
25
Удивительный пост. Всего лишь одна вещь. Java 8 предостерегает от использования параллельных потоков на ресурсах, которые заставят вас блокировать и ждать (например, этот поток ввода), поэтому опция параллельного потока довольно громоздка и не стоит того, нет?
mangusbrother
10
Поддерживает ли параллельный поток порядок строк?
Natix
6
Для чего reset()в примере 11?
Роб Стюарт
2307

Вот способ использования только стандартной библиотеки Java (обратите внимание, что поток не закрыт, ваш пробег может отличаться).

static String convertStreamToString(java.io.InputStream is) {
    java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
    return s.hasNext() ? s.next() : "";
}

Я узнал этот трюк из статьи "Трюки со сканером" . Это работает потому, что Scanner перебирает токены в потоке, и в этом случае мы разделяем токены, используя «начало входной границы» (\ A), что дает нам только один токен для всего содержимого потока.

Обратите внимание: если вам нужно быть конкретным в отношении кодировки входного потока, вы можете предоставить второй аргумент Scannerконструктору, который указывает, какой набор символов использовать (например, «UTF-8»).

Наконечник шляпы идет также к Джейкобу , который однажды указал мне на упомянутую статью.

Павел Репин
источник
8
Спасибо, для моей версии этого я добавил блок finally, который закрывает поток ввода, так что пользователю не нужно, так как вы закончили чтение ввода. Значительно упрощает код вызывающего абонента.
4
@PavelRepin @Patrick в моем случае, пустой inputStream вызвал NPE во время создания сканера. Я должен был добавить if (is == null) return "";прямо в начале метода; Я считаю, что этот ответ необходимо обновить, чтобы лучше обрабатывать нулевые inputStreams.
CFL_Jeff
115
Для Java 7 вы можете закрыть на пробу с: try(java.util.Scanner s = new java.util.Scanner(is)) { return s.useDelimiter("\\A").hasNext() ? s.next() : ""; }
Earcam
5
К сожалению, это решение, кажется, идет и теряет исключения, выданные в моей базовой реализации потока.
Тайг
11
К сведению, блоки hasNext в потоках ввода консоли (см. Здесь ). (Просто столкнулся с этой проблемой прямо сейчас.) В противном случае это решение работает нормально ... только на голову.
Райан
848

Apache Commons позволяет:

String myString = IOUtils.toString(myInputStream, "UTF-8");

Конечно, вы можете выбрать другие кодировки символов, кроме UTF-8.

Также см .: ( документация )

Chinnery
источник
1
Кроме того, есть метод, который принимает аргумент inputStream только в том случае, если вы нашли кодировку по умолчанию.
Гийом Коте,
13
@Guillaume Coté Я предполагаю, что сообщение заключается в том, что с кодировкой по умолчанию у вас никогда не должно быть «хорошо», поскольку вы не можете быть уверены в том, что это такое, в зависимости от платформы, на которой выполняется код Java.
В Викландере
7
@Per Wiklander Я не согласен с вами. Код, который будет работать на одном, вполне может быть уверен, что кодировка по умолчанию будет в порядке. Для кода, который открывает только локальный файл, разумно попросить их закодировать в кодировке платформы по умолчанию.
Гийом Коте,
39
Для того, чтобы спасти кого - либо хлопот Googling - <зависимость> <идентификатор_группы> org.apache.commons </ идентификатор_группы> <артефакта> Обще-ю </ артефакта> <версия> 1.3.2 </ версия> </ зависимость>
Chris
7
Также небольшое улучшение будет заключаться в использовании константы apache io (или другой) для кодировки символов вместо использования простого строкового литерала - например: IOUtils.toString (myInputStream, Charsets.UTF_8);
300

Принимая во внимание файл, нужно сначала получить java.io.Readerэкземпляр. Затем его можно прочитать и добавить в StringBuilder(нам не нужно, StringBufferесли мы не обращаемся к нему в нескольких потоках, и StringBuilderэто быстрее). Хитрость в том, что мы работаем в блоках, и поэтому не нуждаемся в других потоках буферизации. Размер блока параметризован для оптимизации производительности во время выполнения.

public static String slurp(final InputStream is, final int bufferSize) {
    final char[] buffer = new char[bufferSize];
    final StringBuilder out = new StringBuilder();
    try (Reader in = new InputStreamReader(is, "UTF-8")) {
        for (;;) {
            int rsz = in.read(buffer, 0, buffer.length);
            if (rsz < 0)
                break;
            out.append(buffer, 0, rsz);
        }
    }
    catch (UnsupportedEncodingException ex) {
        /* ... */
    }
    catch (IOException ex) {
        /* ... */
    }
    return out.toString();
}
Paul de Vrieze
источник
8
Это решение использует многобайтовые символы. В этом примере используется кодировка UTF-8, которая позволяет выражать весь диапазон Unicode (включая китайский). Замена «UTF-8» другой кодировкой позволит использовать эту кодировку.
Поль де Вриз
27
@ User1 - мне нравится использовать библиотеки в своем коде, чтобы быстрее выполнять свою работу. Это замечательно, когда ваши менеджеры говорят: «Ух ты, Джеймс! Как ты сделал это так быстро ?!». Но когда нам приходится тратить время на то, чтобы заново изобрести колесо, просто потому, что мы потеряли представление о том, как включить обычную, повторно используемую, опробованную и протестированную утилиту, мы теряем время, которое могли бы потратить на достижение целей нашего проекта. Когда мы изобретаем колесо, мы работаем вдвое больше, но гораздо позже добираемся до финиша. Когда мы доберемся до финиша, никто не сможет нас поздравить.
Строя
10
Извините, после перечитывания моего комментария, он выглядит немного высокомерно. Я просто думаю, что важно иметь вескую причину, чтобы избегать библиотек, и эта причина является допустимой, что вполне может быть :)
jmort253
4
@ jmort253 Мы заметили снижение производительности после нескольких обновлений библиотеки в нашем продукте. К счастью, мы создаем и продаем наш собственный продукт, поэтому у нас нет так называемых сроков. К сожалению, мы создаем продукт, который доступен на многих JVM, базах данных и серверах приложений во многих операционных системах, поэтому мы должны думать о пользователях, использующих некачественные машины ... А оптимизация строковых операций может улучшить производительность на 30 ~ 40%. И исправление: In our product, I even replacedдолжно быть «мы даже заменили».
coolcfan
10
@ jmort253 Если вы уже используете Apache Commons, я бы сказал, пойти на это. В то же время использование библиотек сопряжено с большими затратами (как показывает распространение зависимостей во многих Java-библиотеках Apache). Если это будет единственное использование библиотеки, было бы излишним использовать библиотеку. С другой стороны, определяя размер собственного буфера (ов), вы можете настроить баланс использования памяти и процессора.
Поль де Вриз
248

Использование:

InputStream in = /* Your InputStream */;
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String read;

while ((read=br.readLine()) != null) {
    //System.out.println(read);
    sb.append(read);
}

br.close();
return sb.toString();
sampathpremarathna
источник
11
Дело в том, что вы сначала разбиваетесь на строки, а затем удаляете это. Проще и быстрее читать произвольные буферы.
Поль де Вриз
20
Кроме того, readLine не различает \ n и \ r, поэтому вы не можете снова воспроизвести точный поток.
Мария Ариас де Рейна Домингес
2
очень неэффективно, так как readLineчитать символ за символом, чтобы искать EOL. Кроме того, если в потоке нет разрыва строки, это не имеет смысла.
njzk2
3
@Gops AB: Если вы попробуете это, и в вашем образце будут новые строки, вы увидите, что способ создания этого цикла с использованием readline () и StringBuilder.append () на самом деле не сохраняет новые строки.
Расс Бейтман
4
Это не лучший ответ, потому что он не является строго байтовым. Читатель разбивает новые строки, поэтому вы должны быть осторожны, чтобы поддерживать их.
Джеффри Блатман
173

Если вы используете Google-Collections / Guava, вы можете сделать следующее:

InputStream stream = ...
String content = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8));
Closeables.closeQuietly(stream);

Обратите внимание, что второй параметр (т. Е. Charsets.UTF_8) для объекта InputStreamReaderнеобязателен, но, как правило, рекомендуется указывать кодировку, если вы ее знаете (что следует делать!)

Sakuraba
источник
2
@harschware: задан вопрос: «Если у вас есть объект java.io.InputStream, как вы должны обработать этот объект и создать строку?» Я предположил, что поток уже присутствует в ситуации.
Сакураба
Вы не очень хорошо объяснили свой ответ и имели посторонние переменные; user359996 сказал то же самое, что и вы, но гораздо понятнее.
Уроним
2
+1 для гуавы, -1 для не определения кодировки входного потока. например. новый InputStreamReader (поток, "UTF-8")
Андрас
@Chris Noldus С другой стороны, некоторые люди, как и я, уже имеют в своем проекте гуаву и думают, что это решение более элегантно, чем версия только для SDK.
CorayThan
@Vadzim этот ответ такой же, как этот - оба используют CharStreams.toString
Том
125

Это лучшее решение на чистой Java, которое идеально подходит для Android и любой другой JVM.

Это решение работает удивительно хорошо ... оно простое, быстрое и работает с маленькими и большими потоками одинаково !! (см. контрольный показатель выше. № 8 )

public String readFullyAsString(InputStream inputStream, String encoding)
        throws IOException {
    return readFully(inputStream).toString(encoding);
}

public byte[] readFullyAsBytes(InputStream inputStream)
        throws IOException {
    return readFully(inputStream).toByteArray();
}

private ByteArrayOutputStream readFully(InputStream inputStream)
        throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int length = 0;
    while ((length = inputStream.read(buffer)) != -1) {
        baos.write(buffer, 0, length);
    }
    return baos;
}
TacB0sS
источник
4
Хорошо работает на Android по сравнению с другими ответами, которые работают только в корпоративной Java.
vortexwolf
Сбой в Android с ошибкой OutOfMemory в строке «.write» каждый раз для коротких строк.
Адам
Я добавил кодировку. Как примечание, оригинальный метод readFully, который я имею в своем коде, не возвращает String, он возвращает byte [] для более универсальной функциональности. Реализация новой строки (...) с кодировкой является обязанностью пользователя, использующего API!
TacB0sS
2
Краткое примечание: объем памяти, который это занимает, увеличивается 2*n, где n - размер потока в соответствии с ByteArrayInputStreamавтоматически растущей системой.
njzk2
3
Излишне удваивает использование памяти, что ценно на мобильных устройствах. Вам лучше использовать InputStreamReader и добавить в StringReader, преобразование байта в символ будет выполняться на лету, а не навалом в конце.
Олив
84

Для полноты вот решение Java 9 :

public static String toString(InputStream input) throws IOException {
    return new String(input.readAllBytes(), StandardCharsets.UTF_8);
}

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

Тагир Валеев
источник
Разве метод не выделяет много памяти для чтения? byte[] buf = new byte[DEFAULT_BUFFER_SIZE];где MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;что дает MAX_BUFFER_SIZE = 2147483639. Google говорит, что его около 2,147 ГБ.
Рекин
Извините, я допустил ошибку в расчетах. Это 2 ГБ. Я отредактировал комментарий. Итак, даже если я читаю как файл 4 КБ, я использую 2 ГБ памяти?
Рекин
2
@ChristianHujer, я не вижу этого в последнем коммите jdk8u . AFAIK новые методы никогда не вводятся в обновлениях Java, только в основных выпусках.
Тагир Валеев
4
@ChristianHujer, вопрос был о InputStream, а не о Path. Они InputStreamмогут быть созданы из разных источников, а не только из файлов.
Тагир Валеев
5
Это было написано год назад, поэтому, чтобы подтвердить, я подтверждаю, что этот метод действительно находится в общедоступном выпуске JDK 9. Кроме того, если ваша кодировка "ISO-Latin-1", то это будет чрезвычайно эффективно, поскольку строки Java 9 теперь используют byte[]реализации , если все символы находятся в первых 256 кодовых точках. Это означает, что новая строка (byte [], "ISO-Latin-1") будет простой копией массива.
Klitos Kyriacou
66

Использование:

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;

public static String readInputStreamAsString(InputStream in)
    throws IOException {

    BufferedInputStream bis = new BufferedInputStream(in);
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    int result = bis.read();
    while(result != -1) {
      byte b = (byte)result;
      buf.write(b);
      result = bis.read();
    }
    return buf.toString();
}
Джон Мур
источник
@ DanielDeLeón Нет, это не так. Это BufferedInputStream. Базовые операции чтения составляют 8192 байта за раз.
маркиз Лорн
2
@EJP Я обнаружил, что это медленнее, чем использование BufferedInputStream и чтение в буфер байтового массива вместо одного байта за раз. Пример: 200 мс против 60 мс при чтении файла размером 4,56 МБ.
jk7
Странно, что никто не указал на другую серьезную проблему (да, чтение побайтного содержимого бесполезно даже при буферизации): оно полагается на то, что считается «кодировкой по умолчанию» - это редко хороший способ. Вместо этого обязательно передайте кодировку в качестве аргумента buf.toString().
StaxMan
@ jk7 Время чтения файла размером 4,56 МБ настолько мало, что различия не могут быть значительными.
Маркиз Лорн
63

Вот самое элегантное решение на основе чистой Java (без библиотеки), которое я придумал после некоторых экспериментов:

public static String fromStream(InputStream in) throws IOException
{
    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    StringBuilder out = new StringBuilder();
    String newLine = System.getProperty("line.separator");
    String line;
    while ((line = reader.readLine()) != null) {
        out.append(line);
        out.append(newLine);
    }
    return out.toString();
}
Дрю Ноакс
источник
8
@TorbenKohlmeier, читатели и буферы не нужно закрывать. Предоставленное InputStreamдолжно быть закрыто звонящим.
Дрю Ноакс
7
Не забудьте упомянуть, что в InputStreamReader есть более предпочтительный конструктор, который принимает CharSet.
jontejj
7
почему люди продолжают использовать readLine? если вы не используете линии как таковые, что это хорошо (кроме того, что очень медленно?)
njzk2
4
Не читать по строкам. Что если одна строка такая длинная, чтобы она не помещалась в кучу?
Вохо
4
@voho, если одна строка такая длинная, то нет никакого способа выделить возвращаемое значение в любом случае, которое должно быть равно или больше по размеру этой строке. Если вы имеете дело с файлами такого большого размера, вы должны передавать их в потоковом режиме. Существует множество вариантов использования для загрузки небольших текстовых файлов в память.
Дрю Ноакс
55

Я проверил здесь 14 различных ответов (извините, что не предоставил кредиты, но дубликатов слишком много).

Результат очень удивителен. Оказывается, что Apache IOUtils является самым медленным и ByteArrayOutputStreamсамым быстрым решением:

Итак, сначала вот лучший метод:

public String inputStreamToString(InputStream inputStream) throws IOException {
    try(ByteArrayOutputStream result = new ByteArrayOutputStream()) {
        byte[] buffer = new byte[1024];
        int length;
        while ((length = inputStream.read(buffer)) != -1) {
            result.write(buffer, 0, length);
        }

        return result.toString(UTF_8);
    }
}

Результаты теста 20 МБ случайных байтов за 20 циклов

Время в миллисекундах

  • ByteArrayOutputStreamTest: 194
  • NioStream: 198
  • Java9ISTransferTo: 201
  • Java9ISReadAllBytes: 205
  • BufferedInputStreamVsByteArrayOutputStream: 314
  • ApacheStringWriter2: 574
  • GuavaCharStreams: 589
  • ScannerReaderNoNextTest: 614
  • ScannerReader: 633
  • ApacheStringWriter: 1544
  • StreamApi: ошибка
  • ParallelStreamApi: ошибка
  • BufferReaderTest: Ошибка
  • InputStreamAndStringBuilder: ошибка

Исходный код теста

import com.google.common.io.CharStreams;
import org.apache.commons.io.IOUtils;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

/**
 * Created by Ilya Gazman on 2/13/18.
 */
public class InputStreamToString {


    private static final String UTF_8 = "UTF-8";

    public static void main(String... args) {
        log("App started");
        byte[] bytes = new byte[1024 * 1024];
        new Random().nextBytes(bytes);
        log("Stream is ready\n");

        try {
            test(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void test(byte[] bytes) throws IOException {
        List<Stringify> tests = Arrays.asList(
                new ApacheStringWriter(),
                new ApacheStringWriter2(),
                new NioStream(),
                new ScannerReader(),
                new ScannerReaderNoNextTest(),
                new GuavaCharStreams(),
                new StreamApi(),
                new ParallelStreamApi(),
                new ByteArrayOutputStreamTest(),
                new BufferReaderTest(),
                new BufferedInputStreamVsByteArrayOutputStream(),
                new InputStreamAndStringBuilder(),
                new Java9ISTransferTo(),
                new Java9ISReadAllBytes()
        );

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

        for (Stringify test : tests) {
            try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
                String s = test.inputStreamToString(inputStream);
                if (!s.equals(solution)) {
                    log(test.name() + ": Error");
                    continue;
                }
            }
            long startTime = System.currentTimeMillis();
            for (int i = 0; i < 20; i++) {
                try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
                    test.inputStreamToString(inputStream);
                }
            }
            log(test.name() + ": " + (System.currentTimeMillis() - startTime));
        }
    }

    private static void log(String message) {
        System.out.println(message);
    }

    interface Stringify {
        String inputStreamToString(InputStream inputStream) throws IOException;

        default String name() {
            return this.getClass().getSimpleName();
        }
    }

    static class ApacheStringWriter implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            StringWriter writer = new StringWriter();
            IOUtils.copy(inputStream, writer, UTF_8);
            return writer.toString();
        }
    }

    static class ApacheStringWriter2 implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            return IOUtils.toString(inputStream, UTF_8);
        }
    }

    static class NioStream implements Stringify {

        @Override
        public String inputStreamToString(InputStream in) throws IOException {
            ReadableByteChannel channel = Channels.newChannel(in);
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 16);
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            WritableByteChannel outChannel = Channels.newChannel(bout);
            while (channel.read(byteBuffer) > 0 || byteBuffer.position() > 0) {
                byteBuffer.flip();  //make buffer ready for write
                outChannel.write(byteBuffer);
                byteBuffer.compact(); //make buffer ready for reading
            }
            channel.close();
            outChannel.close();
            return bout.toString(UTF_8);
        }
    }

    static class ScannerReader implements Stringify {

        @Override
        public String inputStreamToString(InputStream is) throws IOException {
            java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
            return s.hasNext() ? s.next() : "";
        }
    }

    static class ScannerReaderNoNextTest implements Stringify {

        @Override
        public String inputStreamToString(InputStream is) throws IOException {
            java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
            return s.next();
        }
    }

    static class GuavaCharStreams implements Stringify {

        @Override
        public String inputStreamToString(InputStream is) throws IOException {
            return CharStreams.toString(new InputStreamReader(
                    is, UTF_8));
        }
    }

    static class StreamApi implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            return new BufferedReader(new InputStreamReader(inputStream))
                    .lines().collect(Collectors.joining("\n"));
        }
    }

    static class ParallelStreamApi implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            return new BufferedReader(new InputStreamReader(inputStream)).lines()
                    .parallel().collect(Collectors.joining("\n"));
        }
    }

    static class ByteArrayOutputStreamTest implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            try(ByteArrayOutputStream result = new ByteArrayOutputStream()) {
                byte[] buffer = new byte[1024];
                int length;
                while ((length = inputStream.read(buffer)) != -1) {
                    result.write(buffer, 0, length);
                }

                return result.toString(UTF_8);
            }
        }
    }

    static class BufferReaderTest implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            String newLine = System.getProperty("line.separator");
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            StringBuilder result = new StringBuilder(UTF_8);
            String line;
            boolean flag = false;
            while ((line = reader.readLine()) != null) {
                result.append(flag ? newLine : "").append(line);
                flag = true;
            }
            return result.toString();
        }
    }

    static class BufferedInputStreamVsByteArrayOutputStream implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            BufferedInputStream bis = new BufferedInputStream(inputStream);
            ByteArrayOutputStream buf = new ByteArrayOutputStream();
            int result = bis.read();
            while (result != -1) {
                buf.write((byte) result);
                result = bis.read();
            }

            return buf.toString(UTF_8);
        }
    }

    static class InputStreamAndStringBuilder implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            int ch;
            StringBuilder sb = new StringBuilder(UTF_8);
            while ((ch = inputStream.read()) != -1)
                sb.append((char) ch);
            return sb.toString();
        }
    }

    static class Java9ISTransferTo implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            inputStream.transferTo(bos);
            return bos.toString(UTF_8);
        }
    }

    static class Java9ISReadAllBytes implements Stringify {

        @Override
        public String inputStreamToString(InputStream inputStream) throws IOException {
            return new String(inputStream.readAllBytes(), UTF_8);
        }
    }

}
Илья Газман
источник
Делать тесты в Java нелегко (особенно из-за JIT). Прочитав исходный код Benchmark, я убедился, что приведенные выше значения не являются точными, и все должны быть осторожны с ними.
Далибор
@Dalibor Вы, вероятно, должны предоставить больше аргументов для своего утверждения, а не просто ссылку.
Илья Газман
Я думаю, что это действительно известный факт, что нелегко сделать свой собственный тест. Для тех, кто этого не знает, есть ссылка;)
Далибор
@Dalibor Я, возможно, не лучший, но у меня есть хорошее представление о тестах Java, поэтому, если вы не сможете указать на конкретную проблему, вы просто вводите в заблуждение, и я не буду продолжать разговор с вами в этих условиях.
Илья Газман
В основном я согласен с Далибором. Вы говорите, что у вас «хорошее понимание тестов Java», но, похоже, вы реализовали наиболее наивный подход, хотя, по-видимому, не знаете об известных проблемах этого подхода. Для начала прочитайте каждый пост по этому вопросу: stackoverflow.com/questions/504103/…
DavidS
41

Я бы использовал некоторые трюки с Java 8.

public static String streamToString(final InputStream inputStream) throws Exception {
    // buffering optional
    try
    (
        final BufferedReader br
           = new BufferedReader(new InputStreamReader(inputStream))
    ) {
        // parallel optional
        return br.lines().parallel().collect(Collectors.joining("\n"));
    } catch (final IOException e) {
        throw new RuntimeException(e);
        // whatever.
    }
}

По сути, такой же, как некоторые другие ответы, за исключением более кратких.

Саймон Куанг
источник
5
Будет ли это return nullкогда-либо называться? Либо br.lines...возврат, либо исключение.
Холлоуэй
3
@ Khaled A Khunaifer: да, довольно уверен ... может быть, вы должны посмотреть здесь: docs.oracle.com/javase/tutorial/essential/exceptions/… . То, что вы ошибочно отредактировали, является заявлением «попробуй с ресурсами».
Jamp
11
Почему вы звоните parallel()в потоке?
Робинст
4
Это не привело бы к честной копии данных, если бы исходный поток использовал окончание строк Windows, так как все \r\nзакончилось бы преобразованием в \n...
Лукас
2
Вы можете использовать, System.lineSeparator()чтобы использовать соответствующий зависимый от платформы конец строки.
Стив К
34

Я провел несколько тестов времени, потому что время имеет значение, всегда.

Я попытался получить ответ в строку 3 разными способами. (показано ниже)
Я упустил блоки try / catch для удобства чтения.

Чтобы дать контекст, это предыдущий код для всех 3 подходов:

   String response;
   String url = "www.blah.com/path?key=value";
   GetMethod method = new GetMethod(url);
   int status = client.executeMethod(method);

1)

 response = method.getResponseBodyAsString();

2)

InputStream resp = method.getResponseBodyAsStream();
InputStreamReader is=new InputStreamReader(resp);
BufferedReader br=new BufferedReader(is);
String read = null;
StringBuffer sb = new StringBuffer();
while((read = br.readLine()) != null) {
    sb.append(read);
}
response = sb.toString();

3)

InputStream iStream  = method.getResponseBodyAsStream();
StringWriter writer = new StringWriter();
IOUtils.copy(iStream, writer, "UTF-8");
response = writer.toString();

Итак, после запуска 500 тестов для каждого подхода с одинаковыми данными запроса / ответа, вот цифры. Опять же, это мои выводы, и ваши выводы могут не совпадать, но я написал это, чтобы дать понять другим различия в эффективности этих подходов.

Ранги:
Подход № 1
Подход № 3 - на 2,6% медленнее, чем # 1
Подход № 2 - на 4,3% медленнее, чем # 1

Любой из этих подходов является подходящим решением для получения ответа и создания из него строки.

Бретт Холт
источник
2
2) содержит ошибку, она всегда добавляет «ноль» в конец строки, так как вы всегда делаете еще один шаг, чем необходимо. В любом случае, производительность будет такой же. Это должно работать: String read = null; StringBuffer sb = new StringBuffer (); while ((read = br.readLine ())! = null) {sb.append (read); }
LukeSolar
Следует отметить, что GetMethod является частью org.apache.commons.httpclient, а не стандартной Java
jk7
Подход № 2 будет использовать '\ n', если файл имеет много строк, это не должно быть ответом
Ninja
33

Чистое решение Java с использованием Stream s, работает с Java 8.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.stream.Collectors;

// ...
public static String inputStreamToString(InputStream is) throws IOException {
    try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
        return br.lines().collect(Collectors.joining(System.lineSeparator()));
    }
}

Как упомянуто Кристоффером Хаммарстромом ниже в другом ответе, безопаснее явно указать кодировку . Т.е. конструктор InputStreamReader может быть изменен следующим образом:

new InputStreamReader(is, Charset.forName("UTF-8"))
Черни
источник
11
Вместо этого Charset.forName("UTF-8")используйте StandardCharsets.UTF_8java.nio.charset).
Робинст
26

Вот более или менее ответ сампата, немного приведенный в порядок и представленный в виде функции:

String streamToString(InputStream in) throws IOException {
  StringBuilder out = new StringBuilder();
  BufferedReader br = new BufferedReader(new InputStreamReader(in));
  for(String line = br.readLine(); line != null; line = br.readLine()) 
    out.append(line);
  br.close();
  return out.toString();
}
ТКН
источник
24

Если вы испытываете приключения, вы можете смешать Scala и Java и получить следующее:

scala.io.Source.fromInputStream(is).mkString("")

Смешивание Java и Scala-кода и библиотек имеет свои преимущества.

См. Полное описание здесь: идиоматический способ преобразования InputStream в строку в Scala

Джек
источник
3
В настоящее время просто это прекрасно работает:Source.fromInputStream(...).mkString
KajMagnus
21

Если вы не можете использовать Commons IO (FileUtils / IOUtils / CopyUtils), вот пример использования BufferedReader для чтения файла построчно:

public class StringFromFile {
    public static void main(String[] args) /*throws UnsupportedEncodingException*/ {
        InputStream is = StringFromFile.class.getResourceAsStream("file.txt");
        BufferedReader br = new BufferedReader(new InputStreamReader(is/*, "UTF-8"*/));
        final int CHARS_PER_PAGE = 5000; //counting spaces
        StringBuilder builder = new StringBuilder(CHARS_PER_PAGE);
        try {
            for(String line=br.readLine(); line!=null; line=br.readLine()) {
                builder.append(line);
                builder.append('\n');
            }
        } 
        catch (IOException ignore) { }

        String text = builder.toString();
        System.out.println(text);
    }
}

Или, если вам нужна грубая скорость, я бы предложил вариант того, что предложил Пол де Вриз (в котором избегается использование StringWriter (который использует StringBuffer внутри):

public class StringFromFileFast {
    public static void main(String[] args) /*throws UnsupportedEncodingException*/ {
        InputStream is = StringFromFileFast.class.getResourceAsStream("file.txt");
        InputStreamReader input = new InputStreamReader(is/*, "UTF-8"*/);
        final int CHARS_PER_PAGE = 5000; //counting spaces
        final char[] buffer = new char[CHARS_PER_PAGE];
        StringBuilder output = new StringBuilder(CHARS_PER_PAGE);
        try {
            for(int read = input.read(buffer, 0, buffer.length);
                    read != -1;
                    read = input.read(buffer, 0, buffer.length)) {
                output.append(buffer, 0, read);
            }
        } catch (IOException ignore) { }

        String text = output.toString();
        System.out.println(text);
    }
}
DJDaveMark
источник
Чтобы заставить ваш код работать, мне пришлось использовать this.getClass (). GetClassLoader (). GetResourceAsStream () (используя Eclipse с проектом maven)
greuze
19

Это хорошо, потому что:

  • Это безопасно обрабатывает Charset.
  • Вы контролируете размер буфера чтения.
  • Вы можете указать длину компоновщика, и она не должна быть точной.
  • Свободен от библиотечных зависимостей.
  • Для Java 7 или выше.

Как это сделать?

public static String convertStreamToString(InputStream is) throws IOException {
   StringBuilder sb = new StringBuilder(2048); // Define a size if you have an idea of it.
   char[] read = new char[128]; // Your buffer size.
   try (InputStreamReader ir = new InputStreamReader(is, StandardCharsets.UTF_8)) {
     for (int i; -1 != (i = ir.read(read)); sb.append(read, 0, i));
   }
   return sb.toString();
}

Для JDK 9

public static String inputStreamString(InputStream inputStream) throws IOException {
    try (inputStream) {
        return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
    }
}
Даниэль Де Леон
источник
1
На catch (Throwable)самом деле не должно быть пустым, если это рабочий код.
Кристиан Худжер
1
что положить в этот броский оператор?
Alex
Хотя использование UTF-8 обычно целесообразно, не следует полагать, что символы закодированы таким образом.
Мартин
18

Это ответ адаптирован из org.apache.commons.io.IOUtils исходного кода , для тех, кто хочет иметь реализацию apache, но не хочет всей библиотеки.

private static final int BUFFER_SIZE = 4 * 1024;

public static String inputStreamToString(InputStream inputStream, String charsetName)
        throws IOException {
    StringBuilder builder = new StringBuilder();
    InputStreamReader reader = new InputStreamReader(inputStream, charsetName);
    char[] buffer = new char[BUFFER_SIZE];
    int length;
    while ((length = reader.read(buffer)) != -1) {
        builder.append(buffer, 0, length);
    }
    return builder.toString();
}
Хай чжан
источник
18

Не забудьте закрыть потоки в конце, если вы используете потоковые ридеры

private String readStream(InputStream iStream) throws IOException {
    //build a Stream Reader, it can read char by char
    InputStreamReader iStreamReader = new InputStreamReader(iStream);
    //build a buffered Reader, so that i can read whole line at once
    BufferedReader bReader = new BufferedReader(iStreamReader);
    String line = null;
    StringBuilder builder = new StringBuilder();
    while((line = bReader.readLine()) != null) {  //Read till end
        builder.append(line);
        builder.append("\n"); // append new line to preserve lines
    }
    bReader.close();         //close all opened stuff
    iStreamReader.close();
    //iStream.close(); //EDIT: Let the creator of the stream close it!
                       // some readers may auto close the inner stream
    return builder.toString();
}

РЕДАКТИРОВАТЬ: В JDK 7+, вы можете использовать конструкцию try-with-resources.

/**
 * Reads the stream into a string
 * @param iStream the input stream
 * @return the string read from the stream
 * @throws IOException when an IO error occurs
 */
private String readStream(InputStream iStream) throws IOException {

    //Buffered reader allows us to read line by line
    try (BufferedReader bReader =
                 new BufferedReader(new InputStreamReader(iStream))){
        StringBuilder builder = new StringBuilder();
        String line;
        while((line = bReader.readLine()) != null) {  //Read till end
            builder.append(line);
            builder.append("\n"); // append new line to preserve lines
        }
        return builder.toString();
    }
}
Тамме Говда
источник
2
Вы правы в отношении закрытия потоков, однако ответственность за закрытие потоков обычно лежит на конструкторе потоков (завершите то, что вы начали). Таким образом, iStreamдействительно должен быть закрыт вызывающим, потому что создатель вызывающий iStream. Кроме того, закрытие потоков должно выполняться в finallyблоке или, что еще лучше, в операторе try-with-resources в Java 7. В вашем коде, когда readLine()бросает IOExceptionили builder.append()бросает OutOfMemoryError, потоки остаются открытыми.
Кристиан Худжер
16

Еще один, для всех пользователей Spring:

import java.nio.charset.StandardCharsets;
import org.springframework.util.FileCopyUtils;

public String convertStreamToString(InputStream is) throws IOException { 
    return new String(FileCopyUtils.copyToByteArray(is), StandardCharsets.UTF_8);
}

Методы утилит in org.springframework.util.StreamUtilsаналогичны методам in FileCopyUtils, но по завершении они оставляют поток открытым.

Джеймс
источник
16

Используйте java.io.InputStream.transferTo (OutputStream), поддерживаемый в Java 9, и ByteArrayOutputStream.toString (String), который принимает имя кодировки:

public static String gobble(InputStream in, String charsetName) throws IOException {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    in.transferTo(bos);
    return bos.toString(charsetName);
}
jmehrens
источник
Что вы дали за имя кодировки в вашем случае?
Вирша
1
@virsha Вы должны определить это по источнику, предоставившему InputStream. Помните, что не имеет смысла иметь строку, не зная, какую кодировку она использует.
Jmehrens
15

Вот полный метод для преобразования InputStreamв Stringбез использования какой - либо сторонней библиотеки. Используйте StringBuilderдля однопоточной среды, иначе используйте StringBuffer.

public static String getString( InputStream is) throws IOException {
    int ch;
    StringBuilder sb = new StringBuilder();
    while((ch = is.read()) != -1)
        sb.append((char)ch);
    return sb.toString();
}
laksys
источник
3
В этом методе кодировка не применяется. Итак, скажем, данные, полученные из InputStream, кодируются с использованием UTF-8, вывод будет неправильным. Чтобы это исправить, вы можете использовать in = new InputStreamReader(inputStream)и (char)in.read().
Фредерик Лейтенбергер,
2
и память неэффективна; Я полагаю, что я пытался использовать это раньше на большом входе, и
StringBuilder не хватило
1
Есть другой аналогичный ответ, который использует буфер char [], более эффективен и заботится о charset.
Гийом Перро,
14

Вот как это сделать, используя только JDK, используя буферы байтового массива. Вот как IOUtils.copy()все методы commons-io работают. Вы можете заменить byte[]на, char[]если вы копируете с Readerвместо InputStream.

import java.io.ByteArrayOutputStream;
import java.io.InputStream;

...

InputStream is = ....
ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);
byte[] buffer = new byte[8192];
int count = 0;
try {
  while ((count = is.read(buffer)) != -1) {
    baos.write(buffer, 0, count);
  }
}
finally {
  try {
    is.close();
  }
  catch (Exception ignore) {
  }
}

String charset = "UTF-8";
String inputStreamAsString = baos.toString(charset);
Мэтт Шеннон
источник
1
Пожалуйста, дайте описание того, что вы пытаетесь достичь.
Рагунатх Джавахар
14

Пользователи Kotlin просто делают:

println(InputStreamReader(is).readText())

в то время как

readText()

является встроенным методом расширения стандартной библиотеки Kotlin.

Alex
источник
Это на самом деле не совсем правильно, потому что это не закрывает поток. Я бы порекомендовал is.bufferedReader().use { it.readText() }.
Макс
9

Самый простой способ в JDK - использовать следующие фрагменты кода.

String convertToString(InputStream in){
    String resource = new Scanner(in).useDelimiter("\\Z").next();
    return resource;
}
Рагу К Наир
источник
7

Вот мое решение на основе Java 8 , которое использует новый Stream API для сбора всех строк из InputStream:

public static String toString(InputStream inputStream) {
    BufferedReader reader = new BufferedReader(
        new InputStreamReader(inputStream));
    return reader.lines().collect(Collectors.joining(
        System.getProperty("line.separator")));
}
Кристиан Редель
источник
1
Кажется, что вы на самом деле не прочитали все ответы, опубликованные ранее. Версия Stream API уже была здесь как минимум два раза .
Тагир Валеев
Я посмотрел на все решения, но не нашел подходящих. Я считаю, что две строки с кратким описанием точно представлены. Например, блок try-catch из другого решения никогда не используется. Но ты прав. С таким количеством ответов я переключился в режим быстрого пропуска-чтения ... :-)
Кристиан Редель
1
Вы не читаете исходный файл, вы конвертируете любые окончания строк, которые есть в файле, в любые окончания строк в ОС, возможно, изменяя содержимое файла.
Кристиан Худжер
7

С точки зрения reduce, и concatэто может быть выражено в Java 8 как:

String fromFile = new BufferedReader(new   
InputStreamReader(inputStream)).lines().reduce(String::concat).get();
libnull-DEV
источник
1
Это будет безумно медленно.
Тагир Валеев
Интересно, а почему? Не могли бы вы уточнить?
libnull-dev
1
Разве вы не знаете, почему объединение строк в цикле вместо использования StringBuilder - плохая идея?
Тагир Валеев
Вы правы. StringBuilderможет быть более эффективным. Я проверю, но моей целью было показать более функциональный подход с неизменяемым String.
libnull-dev
Функциональные подходы крутые, но обычно очень неэффективные.
Луис Мартинес
4

Ответ JDK 7/8, который закрывает поток и все еще выбрасывает IOException:

StringBuilder build = new StringBuilder();
byte[] buf = new byte[1024];
int length;
try (InputStream is = getInputStream()) {
  while ((length = is.read(buf)) != -1) {
    build.append(new String(buf, 0, length));
  }
}
Брайан Понтарелли
источник