Java 裡把 InputStream 轉換成 String 的幾種方法
原文連結 http://unmi.cc/java-convert-inputstream-to-string/來自 隔葉黃鶯
Unmi Blog
另可參考http://www.chengxuyuans.com/qa/java/86209.html
我們在 Java 中經常會碰到如何把 InputStream 轉換成 String 的情形,比如從檔案或網路得到一個 InputStream,需要轉換成字串輸出或賦給別的變數。
未真正關注這個問題之前我常用的辦法就是按位元組一次次讀到緩衝區,或是建立 BufferedReader 逐行讀取。其實大可不必費此周折,我們可以用 Apache commons IOUtils,或者是 JDK 1.5 後的 Scanner,還可用 Google Guava 庫的 CharStreams。到了 JDK7,若要從檔案中直接得到字串還能用 java.nio.file.Files#readAllLines 和 java.nio.file.Files#readAllBytes 方法。
下面看各個例子,為能夠實際用運,例子寫在 main 方法裡,並從檔案獲得一個 InputStream,程式碼中把可能要捕獲的異常丟擲來。再就是注意處理輸入輸出流時有涉及到字符集,字符集亂了就亂碼了,預設字符集是 System.getProperty("file.encoding"),通常我們都用 UTF-8,異常 UnsupportedEncodingException 繼承自 IOException。
下面的 6 個方法中應該有一個你能看得上的吧,用 Groovy,Scala 的除外,若未找到一個遂意的,告訴我,你有好辦法更應該告訴我。
1. 使用 JDK 5 的 Scanner
package cc.unmi.test; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.Scanner; /** * * @author Unmi * @Creation date: 2013-02-01 */ public class Test { /** * @param args * @throws FileNotFoundException */ public static void main(String[] args) throws FileNotFoundException { InputStream inputStream = new FileInputStream("d:/sample.txt"); Scanner scanner = new Scanner(inputStream, "UTF-8"); String text = scanner.useDelimiter("\\A").next(); System.out.println(text); scanner.close(); } }
2. JDK1.4 及之前的 BufferedReader 法
中間那些判斷是不是第一行來決定是否加換行符是些雜音。package cc.unmi.test; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; /** * * @author Unmi * @Creation date: 2013-02-01 */ public class Test { /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { InputStream inputStream = new FileInputStream("d:/sample.txt"); StringBuilder stringBuilder = new StringBuilder(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); boolean firstLine = true; String line = null; ; while((line = bufferedReader.readLine()) != null){ if(!firstLine){ stringBuilder.append(System.getProperty("line.separator")); }else{ firstLine = false; } stringBuilder.append(line); } System.out.println(stringBuilder.toString()); } }
3. JDK1.4 及之前的 readBytes 法
package cc.unmi.test;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
*
* @author Unmi
* @Creation date: 2013-02-01
*/
public class Test {
/**
* @throws IOException
*/
public static void main(String[] args) throws IOException {
InputStream inputStream = new FileInputStream("d:/sample.txt");
byte[] buffer = new byte[2048];
int readBytes = 0;
StringBuilder stringBuilder = new StringBuilder();
while((readBytes = inputStream.read(buffer)) > 0){
stringBuilder.append(new String(buffer, 0, readBytes));
}
System.out.println(stringBuilder.toString());
}
}
緩衝區的大小自己根據實際來調,比 BufferedReader 還簡潔些,不需管換行符的事情。
4. Apache commons IOUtils.toString 法
package cc.unmi.test;
import java.io.*;
import org.apache.commons.io.IOUtils;
/**
*
* @author Unmi
* @Creation date: 2013-02-01
*/
public class Test {
/**
* @throws IOException
*/
public static void main(String[] args) throws IOException {
InputStream inputStream = new FileInputStream("d:/sample.txt");
String text = IOUtils.toString(inputStream);
System.out.println(text);
}
}
第三方庫就是第三方庫,人家充分考慮到了你的感受,你對 JDK 庫的抱怨,多簡潔,一行搞定。IOUtils 還能把內容拷入其他的 Writer 中,如 IOUtils.copy(inputStream, new StringWriter())。
5. Google guava 的 CharStreams 方法
package cc.unmi.test;
import java.io.*;
import com.google.common.io.CharStreams;
/**
*
* @author Unmi
* @Creation date: 2013-02-01
*/
public class Test {
/**
* @throws IOException
*/
public static void main(String[] args) throws IOException {
InputStream inputStream = new FileInputStream("d:/sample.txt");
String text = CharStreams.toString(new InputStreamReader(inputStream, "UTF-8"));
System.out.println(text);
}
}
CharSteams 不是直接作用在 InputSteam 上的,還要靠 InputStreamReader 拱個橋。
6. JDK 7 的 NIO readAllBytes
package cc.unmi.test;
import java.io.IOException;
import java.nio.file.*;
/**
*
* @author Unmi
* @Creation date: 2013-02-01
*/
public class Test {
/**
* @throws IOException
*/
public static void main(String[] args) throws IOException {
byte[] bytes = Files.readAllBytes(Paths.get("d:/sample.txt"));
String text = new String(bytes);
System.out.println(text);
}
}
這讓我們相信 JDK 一直還有人在管,雖然不可能象動態語言的方法那麼快捷,上面的 readAllBytes 在處理大檔案時肯定會很被動的。而 Files.readAllLines
會把檔案的內容讀入一個 List<String> 物件中,往記憶體不斷放東西就得掂量下記憶體會不會被爆。在 java.nio.file.* 還有很多新事物可供發掘。