Як я можу прочитати / перетворити InputStream у рядок на Java?


4063

Якщо у вас є java.io.InputStreamоб'єкт, як слід обробити цей об'єкт і створити String?


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

Який найпростіший спосіб взяти InputStreamта перетворити його на String?

public String convertStreamToString(InputStream is) {
    // ???
}

36
Відповіді на це питання тільки роботу , якщо ви хочете , щоб прочитати вміст потоку , в повній мірі (поки вона не буде закрита). Оскільки це не завжди призначено (http-запити з підтримкою живого зв'язку не будуть закриті), цей метод викликає блокування (не надаючи вам вмісту).
f1sh

21
Вам потрібно знати та вказати кодування символів для потоку, або у вас з’являться помилки кодування символів, оскільки ви будете використовувати довільно вибране кодування залежно від того, на якій машині / операційній системі / платформі чи його версії працює код. Тобто не використовуйте методи, які залежать від кодування платформи за замовчуванням.
Крістофер Хаммарстрем

11
Тільки для того, щоб розважитися власним коментарем 9 років тому, я сьогодні використовую текст "String s = new File (" SomeFile.txt "). Groovy" Groovy ") для того, щоб прочитати весь файл відразу і він чудово працює. Я задоволений тим, що використовую 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"));що є настільки ж хорошим, як і мова, який ніколи не підтримуватиме такі магічні перетворення типу, як описаний вами.
Холгер

Відповіді:


2530

Гарний спосіб зробити це - використання спільноти Apache 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
Для андроїд розробників, схоже, андроїд не поставляється з IOUtils від Apache. Тож ви можете поглянути на інші відповіді.
Chris.Zou

47
На даний момент це неймовірно давнє питання (його задали у 2008 році). Варто свого часу прочитати більш сучасні відповіді. Деякі користуються власними дзвінками з бібліотеки Java 8.
Шадоніня

36
Ця відповідь сильно застаріла, і треба мати змогу позначити її як таку (на жаль, це не можливо).
codepleb

7
IOUtils.toString () давно застарів. Ця відповідь вже точно не є рекомендованим способом.
Рошан

7
потім відредагуйте його, щоб пояснити, чому це застаріло, щоб допомогти майбутнім читачам.
Жан-Франсуа Фабре

2486

Узагальнивши інші відповіді, я знайшов 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. Використання потокового API (Java 8). Попередження : це рішення перетворює різні розриви рядків (як \r\n) у \n.

    String result = new BufferedReader(new InputStreamReader(inputStream))
      .lines().collect(Collectors.joining("\n"));
    
  5. Використання паралельного API Stream (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
Оновлений; найсмішніше, що результати більш ніж очікувані: слід використовувати стандартний синтаксичний цукор JDK та / або Apache Commons.
Олексій Матюшкін

25
Дивовижний пост. Тільки одне. Java 8 застерігає від використання паралельних потоків на ресурсах, які змусять вас заблокувати та чекати (наприклад, цей вхідний потік), тому параметр паралельного потоку досить громіздкий і не варто цього ні?
манґббротер

10
Чи підтримує паралельний потік насправді впорядкування рядків?
Натікс

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() : "";
}

Цей трюк я дізнався із статті "Дурні хитрості сканера" . Причина, яка працює, полягає в тому, що Сканер повторює маркери в потоці, і в цьому випадку ми відокремлюємо маркери, використовуючи "початок вхідної межі" (\ A), тим самим даючи нам лише один маркер для всього вмісту потоку.

Зауважте, якщо вам потрібно конкретизувати кодування вхідного потоку, ви можете надати Scannerконструктору другий аргумент, який вказує, який набір символів використовувати (наприклад, "UTF-8").

Підказка капелюха також стосується Якова , який одного разу вказав мені на зазначену статтю.


8
Дякую, для моєї версії цього я додав остаточний блок, який закриває вхідний потік, тому користувачеві цього не потрібно, оскільки ви закінчили читати дані. Значно спрощує код абонента.

4
@PavelRepin @Patrick в моєму випадку порожній inputStream викликав NPE під час побудови сканера. Мені довелося додати if (is == null) return "";прямо на початку методу; Я вважаю, що цю відповідь потрібно оновити, щоб краще обробляти нульові вхідні потоки.
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
FYI, hasNext блоки на вхідних потоках консолі (див. Тут ). (Щойно я зіткнувся з цим питанням прямо зараз.) Це рішення працює нормально інакше ... лише головою вгору.
Райан

848

Apache Commons дозволяє:

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

Звичайно, ви можете вибрати інші кодування символів, крім UTF-8.

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


1
Також існує метод, який приймає лише аргумент inputStream, якщо ви знайшли кодування за замовчуванням.
Гійом Коте

13
@Guillaume Coté Напевно, повідомлення тут полягає в тому, що ти ніколи не повинен бути «добре з кодуванням за замовчуванням», оскільки ти не можеш бути впевнений у тому, що це таке, залежно від платформи, на якій працює Java-код.
Per Wiklander

7
@Per Wiklander Я не згоден з вами. Код, який буде працювати на одному, може бути повністю впевнений, що кодування за замовчуванням буде нормальним. Для коду, який відкриває лише локальний файл, розумний варіант вимагати їх кодування в кодуванні платформи за замовчуванням.
Гійом Коте

39
Щоб врятувати будь-кого клопоту в Googling - <dependency> <groupId> org.apache.commons </groupId> <artifactId> commons-io </artifactId> <version> 1.3.2 </version> </dependency>
Кріс

7
Також невеликим вдосконаленням буде використання apche 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();
}

8
У цьому рішенні використовуються багатобайтові символи. У прикладі використовується кодування UTF-8, що дозволяє виражати весь діапазон унікодів (у тому числі китайською). Заміна "UTF-8" іншим кодуванням дозволить використовувати це кодування.
Пол де Вріезе

27
@ User1 - Мені подобається використовувати бібліотеки в коді, щоб я міг швидше виконати свою роботу. Дивовижно, коли ваші менеджери кажуть: "Вау Джеймсе! Як це ви зробили так швидко ?!". Але коли нам доводиться витрачати час на винахід колеса лише тому, що ми помилилися з ідеями щодо включення загальної, багаторазової, перевіреної утиліти, ми втрачаємо час, який ми могли б витратити на просування цілей нашого проекту. Коли ми винаходимо колесо, ми працюємо вдвічі важче, але добираємось до фінішу набагато пізніше. Після того, як ми на фініші, там немає кого привітати.
Будуючи

10
Вибачте, після перечитання мого коментаря він виходить трохи зарозумілим. Я просто думаю, що важливо мати вагому причину уникати бібліотек, і це причина є дійсною, що там дуже добре може бути :)
jmort253

4
@ jmort253 Ми помітили регресію продуктивності після того, як кілька разів оновлювали деяку бібліотеку нашого продукту. На щастя, ми будуємо та продаємо власний товар, тому насправді не існує так званих термінів. На жаль, ми будуємо продукт, який доступний на багатьох JVM, базах даних та серверах додатків у багатьох операційних системах, тому нам доводиться думати про користувачів, які використовують погані машини ... І оптимізація строкових операцій може покращити якість роботи на 30 ~ 40%. І виправлення: In our product, I even replacedмає бути "нас навіть замінили".
coolcfan

10
@ jmort253 Якщо ви вже користуєтеся апаш-спільнотою, я б сказав, перейдіть до цього. У той же час використання бібліотек є реальною вартістю (як показує поширення залежності у багатьох бібліотеках apache java). Якщо це буде єдиним використанням бібліотеки, було б надмірно використовувати бібліотеку. З іншого боку, визначаючи свій власний розмір буфера, ви можете налаштувати баланс використання пам'яті / процесора.
Пол де Вріезе

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();

11
Річ у тому, що ви спочатку розділяєте їх на рядки, а потім скасовуєте це. Простіше і швидше просто читати довільні буфери.
Пол де Врієзе

20
Крім того, readLine не розрізняє \ n і \ r, тому ви не зможете знову відтворити точний потік.
Марія Аріас де Рейна Домінгес

2
дуже неефективно, так як readLineчитати персонаж за символом, щоб шукати EOL. Крім того, якщо в потоці немає розриву лінії, це насправді не має сенсу.
njzk2

3
@Gops AB: Якщо ви спробуєте це, і у вашому зразку були нові рядки, ви побачите, що спосіб створення цього циклу за допомогою readline () та StringBuilder.append () насправді не зберігає нові рядки.
Russ Bateman

4
Це не найкраща відповідь, тому що це не суворо байт у байті. Читач чіпляє нові рядки, тому вам потрібно бути обережними, щоб підтримувати їх.
Джефрі Блатман

173

Якщо ви використовуєте Google-Collections / Guava, ви можете зробити наступне:

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

Зауважте, що другий параметр (тобто Charsets.UTF_8) для цього InputStreamReaderне потрібен, але, як правило, корисно вказати кодування, якщо ви знаєте його (що вам слід!)


2
@harschware: Враховуючи питання: "Якщо у вас є об'єкт java.io.InputStream, як слід обробити цей об'єкт і створити String?" Я припускав, що в ситуації вже присутній потік.
Сакураба

Ви не дуже добре пояснили свою відповідь і мали сторонні змінні; user359996 сказав те саме, що і ви, але набагато чіткіше.
Уронім

2
+1 для guava, -1 для невказання кодування вхідного потоку. напр. новий InputStreamReader (потік, "UTF-8")
andras

@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;
}

4
Добре працює на Android порівняно з іншими відповідями, які працюють лише у корпоративній Java.
вихровий вовк

Збій в Android з помилкою OutOfMemory у рядку ".write" щоразу для коротких рядків.
Адам

Я додав кодування. як бічна примітка, оригінальний метод readFully, який я маю в своєму коді, не повертає String, він повертає байт [] для більш загальної функції. Реалізація нової String (...) з кодуванням - це відповідальність того, хто використовує API!
TacB0sS

2
Швидка примітка: слід пам’яті цього значення позначається 2*n, де n - розмір потоку, відповідно до системи ByteArrayInputStreamавтоматичного росту.
njzk2

3
Зайве подвоєння використання пам’яті, що дорогоцінно на мобільних пристроях. Ви краще скористайтеся InputStreamReader та додайте до StringReader, перетворення байтів у char буде здійснено на ходу, а не в кінці в кінці.
Олів

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 кодових точках. Це означає, що нова String (байт [], "ISO-Latin-1") буде простою копією масиву.
Клітос Кіріако

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 байти.
користувач207421

2
@EJP Я знайшов , що це буде повільніше , ніж при використанні BufferedInputStream і читання в масив байт буфера замість одного байта за раз. Приклад: 200ms vs 60ms при читанні файлу 4,56 MiB.
jk7

Як не дивно, що тут ніхто не вказав на іншу головну проблему (так, читання вмісту в байтах за байтом марно навіть при буферизації): воно покладається на те, що трапляється як "кодування за замовчуванням" - це рідко є хорошим способом. Натомість переконайтеся, що передайте кодування як аргумент buf.toString().
StaxMan

@ jk7 Час для читання файлу 4,56 Мб настільки крихітний, що різниці не могли бути істотними.
користувач207421

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
Не читайте по рядках. Що робити, якщо один рядок такий довгий, щоб він не вміщувався до купи?
voho

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
  • Java9ISTрансферTo: 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 Я, мабуть, не найкращий, але я добре розумію орієнтири 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/… . Те, що ви неправильно відредагували, - це заява "випробування ресурсів".
джамп

11
Чому ви дзвоните parallel()по потоку?
Робінст

4
Це не призвело б до чесної копії даних, якби джерело використовував закінчення вікон рядків, оскільки все \r\nв кінцевому підсумку перетворюється на \n...
Лукас

2
Ви можете використовувати System.lineSeparator()для використання відповідного рядка, що залежить від платформи.
Стів К

34

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

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

Для контексту, це попередній код для всіх 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) містить помилку, вона додає завжди "null" в кінці рядка, оскільки ви завжди робите ще один крок, ніж це необхідно. Я думаю, що продуктивність буде однаковою. Це повинно працювати: String read = null; StringBuffer sb = новий 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_8(від java.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 у String у 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);
    }
}

Для того, щоб ваш код працював, мені довелося скористатися this.getClass (). GetClassLoader (). GetResourceAsStream () (використовуючи Eclipse для проекту Maven)
мастило

19

Це добре, тому що:

  • Він безпечно поводиться з Шарсетом.
  • Ви керуєте розміром буфера для читання.
  • Ви можете вказати довжину будівельника, і це не повинно бути точним значенням.
  • Без вільних залежностей від бібліотеки.
  • Для 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();
}

EDIT: У JDK 7+ ви можете скористатися конструкцією "спробувати ресурси".

/**
 * 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блоці, а ще краще в операторі 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);
}

Методи корисних програм у org.springframework.util.StreamUtilsподібні до тих, що в 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);
}

Що ви передали для назви шаблону у вашому випадку?
virsha

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();
}

3
У цьому методі не застосовується кодування. Отже, скажімо, що дані, отримані від InputStream, кодуються за допомогою UTF-8, вихід буде неправильним. Для виправлення цього ви можете скористатися in = new InputStreamReader(inputStream)і (char)in.read().
Фредерік Лейтенбергер

2
і неефективна пам'ять; Я вважаю, що я намагався використовувати це раніше на великому
вкладі,

1
Є ще одна подібна відповідь, яка використовує буфер char [] і є більш ефективною та піклується про charset.
Гійом Перро

14

Ось як це зробити, використовуючи лише JDK, використовуючи байтові буфери масиву. Це фактично так, як працюють всі загальнодоступні IOUtils.copy()методи. Ви можете замінити 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()

- це стандартний метод розширення бібліотеки Котліна.


Це насправді не зовсім правильно, оскільки воно не закриває потік. Я б рекомендував 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
Здається, ви насправді не прочитали всіх відповідей, розміщених раніше. Версія API Stream вже була тут щонайменше два рази .
Тагір Валєєв

Я переглянув усі рішення, але не знайшов підходящого. Я знаходжу два рядки з коротким описом, точно представлені. Наприклад, блок "try-catch" з іншого рішення ніколи не використовується. Але ти маєш рацію. Із такою кількістю відповідей я перейшов на швидкий пропуск у режимі читання ... :-)
Крістіан Радель

1
Ви не читаєте оригінальний файл, ви перетворюєте будь-які рядкові закінчення файлу в ті, що закінчуються в ОС, можливо, змінюючи вміст файлу.
Крістіан Худжер

7

У термінах reduce, і concatце може бути виражено в Java 8 як:

String fromFile = new BufferedReader(new   
InputStreamReader(inputStream)).lines().reduce(String::concat).get();

1
Це буде шалено повільно.
Тагір Валєєв

Цікаво, чому? Не могли б ви детальніше?
libnull-dev

1
Ви не знаєте, чому об'єднання рядків у циклі замість використання StringBuilder - це погана ідея?
Тагір Валєєв

Ти правий. StringBuilderможе бути ефективнішим. Я перевірю, але моя суть полягала в тому, щоб показати більш функціональний підхід із незмінним String.
libnull-dev

Функціональні підходи класні, але зазвичай дуже неефективні.
Lluis Martinez

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