1. 概要

このチュートリアルでは、InputStreamを文字列に変換する方法を見ていきます。

まず、Java 8/9ソリューションを含むプレーンなJavaを使用し、次にGuavaおよびApacheCommonsIOライブラリの使用についても検討します。

この記事は、ここBaeldungの「Java –BacktoBasic」シリーズの一部です。

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にもたらします。 これを使用してInputStreamString:に変換する方法を見てみましょう。

@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()を使用する場合、作成されたStringに使用するEOLのタイプを明示的に決定する必要があります。

Collectors.joining(System.lineSeparator())を使用することもできます。この場合、出力はシステム設定によって異なります。

4. Java 9で変換– InputStream.readAllBytes()

Java 9以降を使用している場合は、 InputStream:に追加された新しいreadAllBytesメソッドを利用できます。

@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()呼び出しが入力ストリーム全体を読み取ることを意味します。

これがJava5の例ではなく、Java 7の例である唯一の理由は、try-with-resourcesステートメントの使用です。 これを標準のtry-finallyブロックに変換すると、Java5で問題なくコンパイルされます。

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()メソッドを使用してファイルコンテンツをStringに変換します。

8. グアバでの変換

ByteSource機能を活用するGuavaの例から始めましょう:

@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 InputStreamByteSource、にラップします。私たちが知る限り、これが最も簡単な方法です。
  • then ByteSourceをUTF8文字セットを使用したCharSourceと見なします。
  • 最後に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. ApacheCommonsIOを使用した変換

次に、CommonsIOライブラリを使用してこれを行う方法を見てみましょう。

ここでの重要な注意点は、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およびApacheCommonsIOライブラリの使用方法を検討しました。

これらすべての例とコードスニペットの実装は、GitHubから入手できます。