Перейти к основному содержимому

Java InputStream в строку

· 6 мин. чтения

1. Обзор

В этом руководстве мы рассмотрим, как преобразовать InputStream в строку.

Мы начнем с использования простой Java, включая решения Java8/9, а затем также рассмотрим использование библиотек ввода-вывода Guava и Apache Commons .

Эта статья является частью серии «Java — Back to Basic» здесь, на ForEach.

2. Преобразование с помощью Java — StringBuilder

Давайте рассмотрим простой низкоуровневый подход с использованием простой Java, InputStream и простого StringBuilder :

@Test
public void givenUsingJava5_whenConvertingAnInputStreamToAString_thenCorrect()
throws IOException {
String originalString = randomAlphabetic(DEFAULT_SIZE);
InputStream inputStream = new ByteArrayInputStream(originalString.getBytes());

StringBuilder textBuilder = new StringBuilder();
try (Reader reader = new BufferedReader(new InputStreamReader
(inputStream, Charset.forName(StandardCharsets.UTF_8.name())))) {
int c = 0;
while ((c = reader.read()) != -1) {
textBuilder.append((char) c);
}
}
assertEquals(textBuilder.toString(), originalString);
}

3. Преобразование с помощью Java 8 — BufferedReader

В Java 8 добавлен новый метод lines() для BufferedReader . Давайте посмотрим, как мы можем использовать его для преобразования InputStream в String:

@Test
public void givenUsingJava8_whenConvertingAnInputStreamToAString_thenCorrect() {
String originalString = randomAlphabetic(DEFAULT_SIZE);
InputStream inputStream = new ByteArrayInputStream(originalString.getBytes());

String text = new BufferedReader(
new InputStreamReader(inputStream, StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining("\n"));

assertThat(text, equalTo(originalString));
}

Важно отметить, что lines() использует метод readLine() под капотом. readLine() предполагает, что строка завершается переводом строки («\n»), возвратом каретки («\r») или возвратом каретки, за которым сразу следует перевод строки. Другими словами, он поддерживает все распространенные стили End Of Line : Unix, Windows и даже старые Mac OS.

С другой стороны, когда мы используем Collectors.joining() , нам нужно явно решить, какой тип EOL мы хотим использовать для созданной строки .

Мы также могли бы использовать Collectors.joining(System.lineSeparator()) , и в этом случае вывод зависит от настроек системы.

4. Преобразование с помощью Java 9 — InputStream.readAllBytes()

Если мы используем Java 9 или выше, мы можем использовать новый метод readAllBytes , добавленный в InputStream:

@Test
public void givenUsingJava9_whenConvertingAnInputStreamToAString_thenCorrect() throws IOException {
String originalString = randomAlphabetic(DEFAULT_SIZE);
InputStream inputStream = new ByteArrayInputStream(originalString.getBytes());

String text = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);

assertThat(text, equalTo(originalString));
}

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

5. Преобразование с помощью Java и сканера

Далее давайте рассмотрим простой пример Java с использованием стандартного текстового сканера :

@Test
public void givenUsingJava7_whenConvertingAnInputStreamToAString_thenCorrect()
throws IOException {
String originalString = randomAlphabetic(8);
InputStream inputStream = new ByteArrayInputStream(originalString.getBytes());

String text = null;
try (Scanner scanner = new Scanner(inputStream, StandardCharsets.UTF_8.name())) {
text = scanner.useDelimiter("\\A").next();
}

assertThat(text, equalTo(originalString));
}

Обратите внимание, что InputStream будет закрыт при закрытии Scanner .

Также стоит уточнить, что делает useDelimiter("\\A") . Здесь мы передали '\A', регулярное выражение маркера границы, обозначающее начало ввода. По сути, это означает, что вызов next() считывает весь входной поток.

Единственная причина, по которой это пример для Java 7, а не для Java 5, заключается в использовании оператора try-with-resources . Если мы превратим это в стандартный блок try-finally , он отлично скомпилируется с Java 5.

6. Преобразование с использованием ByteArrayOutputStream

Наконец, давайте рассмотрим еще один простой пример Java, на этот раз с использованием класса ByteArrayOutputStream :

@Test
public void givenUsingPlainJava_whenConvertingAnInputStreamToString_thenCorrect()
throws IOException {
String originalString = randomAlphabetic(8);
InputStream inputStream = new ByteArrayInputStream(originalString.getBytes());

ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[1024];
while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}

buffer.flush();
byte[] byteArray = buffer.toByteArray();

String text = new String(byteArray, StandardCharsets.UTF_8);
assertThat(text, equalTo(originalString));
}

В этом примере InputStream преобразуется в ByteArrayOutputStream путем чтения и записи блоков байтов. Затем OutputStream преобразуется в массив байтов, который используется для создания String .

7. Преобразование с помощью java.nio

Другое решение — скопировать содержимое InputStream в файл, а затем преобразовать его в строку:

@Test
public void givenUsingTempFile_whenConvertingAnInputStreamToAString_thenCorrect()
throws IOException {
String originalString = randomAlphabetic(DEFAULT_SIZE);
InputStream inputStream = new ByteArrayInputStream(originalString.getBytes());

Path tempFile =
Files.createTempDirectory("").resolve(UUID.randomUUID().toString() + ".tmp");
Files.copy(inputStream, tempFile, StandardCopyOption.REPLACE_EXISTING);
String result = new String(Files.readAllBytes(tempFile));

assertThat(result, equalTo(originalString));
}

Здесь мы используем класс java.nio.file.Files для создания временного файла, а также для копирования содержимого InputStream в файл. Затем тот же класс используется для преобразования содержимого файла в строку с помощью метода readAllBytes() .

8. Преобразование с помощью гуавы

Давайте начнем с примера Guava, использующего функциональность ByteSource :

@Test
public void givenUsingGuava_whenConvertingAnInputStreamToAString_thenCorrect()
throws IOException {
String originalString = randomAlphabetic(8);
InputStream inputStream = new ByteArrayInputStream(originalString.getBytes());

ByteSource byteSource = new ByteSource() {
@Override
public InputStream openStream() throws IOException {
return inputStream;
}
};

String text = byteSource.asCharSource(Charsets.UTF_8).read();

assertThat(text, equalTo(originalString));
}

Пройдемся по шагам:

  • во- первых , мы оборачиваем наш InputStream в ByteSource, и, насколько нам известно, это самый простой способ сделать это.
  • затем — мы рассматриваем наш ByteSource как CharSource с кодировкой UTF8.
  • наконец — мы используем CharSource , чтобы прочитать его как строку.

Более простой способ выполнить преобразование — использовать Guava , но поток должен быть явно закрыт; к счастью, мы можем просто использовать синтаксис try-with-resources, чтобы позаботиться об этом:

@Test
public void givenUsingGuavaAndJava7_whenConvertingAnInputStreamToAString_thenCorrect()
throws IOException {
String originalString = randomAlphabetic(8);
InputStream inputStream = new ByteArrayInputStream(originalString.getBytes());

String text = null;
try (Reader reader = new InputStreamReader(inputStream)) {
text = CharStreams.toString(reader);
}

assertThat(text, equalTo(originalString));
}

9. Преобразование с помощью Apache Commons IO

Теперь давайте посмотрим, как это сделать с библиотекой Commons IO.

Важным предостережением здесь является то, что, в отличие от Guava, ни один из этих примеров не закроет InputStream:

@Test
public void givenUsingCommonsIo_whenConvertingAnInputStreamToAString_thenCorrect()
throws IOException {
String originalString = randomAlphabetic(8);
InputStream inputStream = new ByteArrayInputStream(originalString.getBytes());

String text = IOUtils.toString(inputStream, StandardCharsets.UTF_8.name());
assertThat(text, equalTo(originalString));
}

Мы также можем использовать StringWriter для преобразования:

@Test
public void givenUsingCommonsIoWithCopy_whenConvertingAnInputStreamToAString_thenCorrect()
throws IOException {
String originalString = randomAlphabetic(8);
InputStream inputStream = new ByteArrayInputStream(originalString.getBytes());

StringWriter writer = new StringWriter();
String encoding = StandardCharsets.UTF_8.name();
IOUtils.copy(inputStream, writer, encoding);

assertThat(writer.toString(), equalTo(originalString));
}

10. Заключение

В этой статье мы узнали, как преобразовать InputStream в строку. Мы начали с использования простой Java, а затем изучили, как использовать библиотеки ввода-вывода Guava и Apache Commons .

Реализация всех этих примеров и фрагментов кода доступна на GitHub .