教你一個小技巧:Inputstream 轉換 String

roc_guo發表於2022-04-18

教你一個小技巧:Inputstream 轉換 String教你一個小技巧:Inputstream 轉換 String
在本教程中,我們將講講如何將一個 InputStream 轉換為一個字串。

我們將從使用普通的 Java 開始,包括 Java 8+ 的解決方案,然後也會研究使用 Guava 和 Apache Commons IO 庫。

用 Java 進行轉換 - StringBuilder

讓我們看看一個簡單的、低階別的方法,使用普通的 Java,一個 InputStream 和一個簡單的 StringBuilder。

@Test
public void convertingAnInputStreamToAString() throws IOException {
    String originalString = randomString(8);
    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);
}
用 Java 8 進行轉換 -- BufferedReader

Java 8 給 BufferedReader 帶來了一個新的 lines() 方法。讓我們看看如何利用它將一個 InputStream 轉換為一個字串。

@Test
public void convertingAnInputStreamToAString() {
    String originalString = randomString(8);
    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")或回車後立即換行中的任何一種結束符。換句話說,它支援所有常見的行結束方式。

另一方面,當我們使用 Collectors.join() 時,我們需要明確決定我們要為建立的 String 使用哪種型別的結束符。

我們也可以使用 Collectors.join(System.lineSeparator()) ,在這種情況下,輸出結果取決於系統設定。

用 Java 9+ 進行轉換 - InputStream.readAllBytes()
如果我們在 Java 9 或以上版本,我們可以利用一個新的 readAllBytes 方法新增到 InputStream 中。

@Test
public void convertingAnInputStreamToAString() throws IOException {
    String originalString = randomString(8);
    InputStream inputStream = new ByteArrayInputStream(originalString.getBytes());
    String text = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
    
    assertThat(text, equalTo(originalString));
}

我們需要注意的是,這段簡單的程式碼是為那些方便將所有位元組讀入位元組陣列的簡單情況準備的。我們不應該用它來讀取有大量資料的輸入流。

用 Java Scanner 進行轉換

接下來,讓我們看看一個使用標準文字掃描器的普通Java例子。

@Test
public void convertingAnInputStreamToAString() throws IOException {
    String originalString = randomString(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() 呼叫讀取了整個輸入流。

使用 ByteArrayOutputStream 進行轉換
最後,讓我們看看另一個普通的Java例子,這次是使用 ByteArrayOutputStream 類。

@Test
public void convertingAnInputStreamToString() throws IOException {
    String originalString = randomString(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 被轉換為一個位元組陣列,用來建立一個字串。

用java.nio進行轉換

另一個解決方案是將 InputStream 的內容複製到一個檔案中,然後將其轉換為一個字串。

@Test
public void convertingAnInputStreamToAString() throws IOException {
    String originalString = randomString(8);
    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() 方法將檔案內容轉換為一個字串。

用Guava進行轉換

讓我們從一個利用 ByteSource 功能的 Guava 例子開始。

@Test
public void convertingAnInputStreamToAString() 
  throws IOException {
    String originalString = randomString(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 看作是一個具有 UTF8 字符集的 CharSource。

最後,我們使用 CharSource 將其作為一個字串來讀取。

一個更簡單的轉換方法是使用 Guava,但需要明確地關閉流, 我們可以簡單地使用 try-with-resources 語法來處理這個問題。

@Test
public void convertingAnInputStreamToAString() throws IOException {
    String originalString = randomString(8);
    InputStream inputStream = new ByteArrayInputStream(originalString.getBytes());
 
    String text = null;
    try (Reader reader = new InputStreamReader(inputStream)) {
        text = CharStreams.toString(reader);
    }
 
    assertThat(text, equalTo(originalString));
}
用 Apache Commons IO 進行轉換

現在讓我們來看看如何用 Commons IO 庫來做這個。

一個重要的注意事項是,與 Guava 不同的是,這些例子都不會關閉 InputStream。

@Test
public void convertingAnInputStreamToAString() throws IOException {
    String originalString = randomString(8);
    InputStream inputStream = new ByteArrayInputStream(originalString.getBytes());
    String text = IOUtils.toString(inputStream, StandardCharsets.UTF_8.name());
    assertThat(text, equalTo(originalString));
}

我們也可以用一個StringWriter來做轉換。
ream 轉換為一個字串。我們從使用普通 Java 開始,然後探索瞭如何使用 Guava 和 Apache Commons IO 庫。

@Test
public void convertingAnInputStreamToAString() throws IOException {
    String originalString = randomString(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));
}


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69901823/viewspace-2887665/,如需轉載,請註明出處,否則將追究法律責任。

相關文章