Inputstream 轉(zhuǎn)換 String,你會(huì)了嗎?
大家好,我是指北君。
在本教程中,我們將講講如何將一個(gè) InputStream 轉(zhuǎn)換為一個(gè)字符串。
我們將從使用普通的 Java 開始,包括 Java 8+ 的解決方案,然后也會(huì)研究使用 Guava 和 Apache Commons IO 庫(kù)。
用 Java 進(jìn)行轉(zhuǎn)換 - StringBuilder
讓我們看看一個(gè)簡(jiǎn)單的、低級(jí)別的方法,使用普通的 Java,一個(gè) InputStream 和一個(gè)簡(jiǎn)單的 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 進(jìn)行轉(zhuǎn)換 -- BufferedReader
Java 8 給 BufferedReader 帶來(lái)了一個(gè)新的 lines() 方法。讓我們看看如何利用它將一個(gè) InputStream 轉(zhuǎn)換為一個(gè)字符串。
@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")或回車后立即換行中的任何一種結(jié)束符。換句話說(shuō),它支持所有常見的行結(jié)束方式。
另一方面,當(dāng)我們使用 Collectors.join() 時(shí),我們需要明確決定我們要為創(chuàng)建的 String 使用哪種類型的結(jié)束符。
我們也可以使用 Collectors.join(System.lineSeparator()) ,在這種情況下,輸出結(jié)果取決于系統(tǒng)設(shè)置。
用 Java 9+ 進(jìn)行轉(zhuǎn)換 - InputStream.readAllBytes()
如果我們?cè)?Java 9 或以上版本,我們可以利用一個(gè)新的 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));
}
我們需要注意的是,這段簡(jiǎn)單的代碼是為那些方便將所有字節(jié)讀入字節(jié)數(shù)組的簡(jiǎn)單情況準(zhǔn)備的。我們不應(yīng)該用它來(lái)讀取有大量數(shù)據(jù)的輸入流。
用 Java Scanner 進(jìn)行轉(zhuǎn)換
接下來(lái),讓我們看看一個(gè)使用標(biāo)準(zhǔn)文本掃描器的普通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));
}
請(qǐng)注意,InputStream 將被關(guān)閉的 Scanner 關(guān)閉。
同樣值得澄清的是 useDelimiter("\A") 的作用。這里我們傳遞了'\A',它是一個(gè)邊界標(biāo)記重碼,表示輸入的開始。本質(zhì)上,這意味著 next() 調(diào)用讀取了整個(gè)輸入流。
使用 ByteArrayOutputStream 進(jìn)行轉(zhuǎn)換
最后,讓我們看看另一個(gè)普通的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));
}
在這個(gè)例子中,InputStream 通過(guò)讀寫字節(jié)塊被轉(zhuǎn)換為 ByteArrayOutputStream。然后 OutputStream 被轉(zhuǎn)換為一個(gè)字節(jié)數(shù)組,用來(lái)創(chuàng)建一個(gè)字符串。
用java.nio進(jìn)行轉(zhuǎn)換
另一個(gè)解決方案是將 InputStream 的內(nèi)容復(fù)制到一個(gè)文件中,然后將其轉(zhuǎn)換為一個(gè)字符串。
@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 類來(lái)創(chuàng)建一個(gè)臨時(shí)文件,同時(shí)將 InputStream 的內(nèi)容復(fù)制到文件中。然后用同一個(gè)類用 readAllBytes() 方法將文件內(nèi)容轉(zhuǎn)換為一個(gè)字符串。
用Guava進(jìn)行轉(zhuǎn)換
讓我們從一個(gè)利用 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));
}
讓我們來(lái)看看這些步驟:
首先,我們把我們的 InputStream 包裝成一個(gè) ByteSource.
其次,我們把 ByteSource 看作是一個(gè)具有 UTF8 字符集的 CharSource。
最后,我們使用 CharSource 將其作為一個(gè)字符串來(lái)讀取。
一個(gè)更簡(jiǎn)單的轉(zhuǎn)換方法是使用 Guava,但需要明確地關(guān)閉流, 我們可以簡(jiǎn)單地使用 try-with-resources 語(yǔ)法來(lái)處理這個(gè)問(wèn)題。
@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 進(jìn)行轉(zhuǎn)換
現(xiàn)在讓我們來(lái)看看如何用 Commons IO 庫(kù)來(lái)做這個(gè)。
一個(gè)重要的注意事項(xiàng)是,與 Guava 不同的是,這些例子都不會(huì)關(guān)閉 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));
}
我們也可以用一個(gè)StringWriter來(lái)做轉(zhuǎn)換。
ream 轉(zhuǎn)換為一個(gè)字符串。我們從使用普通 Java 開始,然后探索了如何使用 Guava 和 Apache Commons IO 庫(kù)。
@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));
}