1. Обзор
В этом руководстве мы рассмотрим, как преобразовать InputStream в строку.
Мы начнем с использования обычной Java, включая решения Java8/9, а затем рассмотрим использование библиотек ввода-вывода Guava и Apache Commons.
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, StandardCharsets.UTF_8))) {
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 в строку:
@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”) или возвратом каретки, за которым сразу следует перевод строки. Другими словами, он поддерживает все распространенные стили завершения строки: Unix, Windows и даже старую Mac OS.
С другой стороны, когда мы используем Collectors.joining(), нам нужно явно решить, какой тип EOL мы хотим использовать для создаваемой строки.
Мы могли бы также использовать Collectors.joining(система.разделитель строк()), в этом случае результат зависит от настроек системы.
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 будет закрыт при закрытии сканера.
Также стоит уточнить, что делает 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 преобразуется в массив байтов, который используется для создания строки.
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
Давайте начнем с примера 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));
}
Давайте пройдемся по ступенькам:
- first – мы преобразуем наш InputStream в ByteSource, и, насколько нам известно, это самый простой способ сделать это.
- then – мы рассматриваем наш байтовый источник как источник символов с кодировкой UTF8.
- finally – мы используем 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.
Важным предостережением здесь является то, что, в отличие от 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.
Оригинал статьи: https://www.baeldung.com/convert-input-stream-to-string