咱們在 Java 中常常會碰到如何把 InputStream 轉換成 String 的情形,好比從文件或網絡獲得一個 InputStream,須要轉換成字符串輸出或賦給別的變量。java
未真正關注這個問題以前我經常使用的辦法就是按字節一次次讀到緩衝區,或是創建 BufferedReader 逐行讀取。其實大可沒必要費此周折,咱們能夠用 Apache commons IOUtils,或者是 JDK 1.5 後的 Scanner,還可用 Google Guava 庫的 CharStreams。到了 JDK7,若要從文件中直接獲得字符串還能用 java.nio.file.Files#readAllLines 和 java.nio.file.Files#readAllBytes 方法。android
下面看各個例子,爲可以實際用運,例子寫在 main 方法裏,並從文件得到一個 InputStream,代碼中把可能要捕獲的異常拋出來。再就是注意處理輸入輸出流時有涉及到字符集,字符集亂了就亂碼了,默認字符集是 System.getProperty("file.encoding"),一般咱們都用 UTF-8,異常 UnsupportedEncodingException 繼承自 IOException。apache
下面的 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 法app
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 法ui
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 還簡潔些,不需管換行符的事情。google
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.* 還有不少新事物可供發掘。
從SDCard保存的txt文件讀取中文到android系統中會出現亂碼問題,如何解決這個亂碼問題,網上有很多解答方法,譬如說利用String temp1 =EncodingUtils.getString(strLine.getBytes(),"GB2312"); 但並不是對全部的狀況都適用,解決亂碼問題首先要明白爲何會亂碼。究其緣由,是由於txt文件在win系統上保存時默認爲ANSI格式,而android目前只支持UTF-8編碼,所以將txt文件的中文讀入android系統中會產生亂碼。也有人說直接將txt另存爲UTF-8編碼格式來解決亂碼問題,但這種方法指標不治本,不能要求用戶手動去更改格式,客戶第一嘛。所以仍是須要想辦法在程序中進行處理。
如下作了一些編碼格式的測試:
測試文本: 122.11196,29.90573,北侖固廢廠 測試代碼段:
reader=new BufferedReader(new FileReader(filename));
strLine=reader.readLine() ;
String temp1 = EncodingUtils.getString(strLine.getBytes(),"GB2312");
String temp2 = EncodingUtils.getString(strLine.getBytes("utf-8"),"utf-8");
String temp3 = EncodingUtils.getString(strLine.getBytes(),"utf-8");
將文件存成 Unicode 格式
將文件存成utf-8 格式
這種方式能獲得非亂碼的中文顯示,但對於 utf-8 格式下取得的經緯度數字利用double lon = Double.parseDouble(lat); 報錯 NumberFormatException,緣由多是
parseDouble(lat)方法不能處理存成utf-8格式的帶標點小數。 將文件 存成 ANSI 格式
將代碼改成:
reader = new BufferedReader(new InputStreamReader(new FileInputStream(filename),"GB2312"));
strLine=reader.readLine() ;
String temp1 = EncodingUtils.getString(strLine.getBytes(),"GB2312");
String temp2 = EncodingUtils.getString(strLine.getBytes("utf-8"),"utf-8");
String temp3 = EncodingUtils.getString(strLine.getBytes(),"utf-8");
即解決了中文亂碼問題,又解決了Double.parseDouble(lat)報錯問題。