需求
直接上代碼
String url = "http://xxx.xxx/xx.txt"; //需要從網(wǎng)絡(luò)讀取的文件
Inputstream is = new URL(url).openStream;
//接下來惕耕,把Inputstream讀成String
然而該stream的編碼未知,且不同文件編碼不同蜜自。默認(rèn)使用utf-8或gb2312都會造成部分結(jié)果亂碼菩貌。
solution
//BufferedInputStream支持mark,可以重復(fù)讀取stream重荠,避免網(wǎng)絡(luò)請求2次
BufferedInputStream is = new BufferedInputStream(new URL(url).openStream());
is.mark(1000000);//10M
//第一次處理stream箭阶,得到encoding
String encoding = new TikaEncodingDetector().guessEncoding(is);
is.reset();
return IOUtils.toString(is, encoding);
解釋
背景知識
心路歷程
首先嘗試stream或file有沒有方法直接getEncoding,得到結(jié)論:
You cannot determine the encoding of a arbitrary byte stream. 如果理解了字符編碼背景知識戈鲁,這個應(yīng)該很容易理解參考那么如何得到一個流的編碼仇参,還是有人做出了工具:
<dependency>
<groupId>org.apache.any23</groupId>
<artifactId>apache-any23-encoding</artifactId>
<version>1.1</version>
</dependency>
public static Charset guessCharset(InputStream is) throws IOException {
return Charset.forName(new TikaEncodingDetector().guessEncoding(is));
}
guessEncoding函數(shù)名很靈性。原理是讀一遍流婆殿,根據(jù)各種編碼特點(diǎn)推斷輸入流的編碼诈乒。既然是guess就不是100%準(zhǔn)的,不過實(shí)用效果不錯鸣皂。感興趣的同學(xué)可以深入一下抓谴。
- guessEncoding已經(jīng)把stream讀過一遍了暮蹂,直接轉(zhuǎn)string得到空字符串。又不想再發(fā)一次網(wǎng)絡(luò)請求重新獲取癌压。然后仰泻,發(fā)現(xiàn)BufferedInputStream支持mark/reset, 重復(fù)讀取。finished滩届,完美集侯。
參考:http://zhangbo-peipei-163-com.iteye.com/blog/2022460
副產(chǎn)品:IO流的關(guān)閉問題
FIleInputStream的finalize方法會調(diào)用close(),即gc時會幫你關(guān)閉io帜消,but棠枉,并不建議這樣做。理由:
- 資源沒有被及時釋放泡挺;
- finalize方法調(diào)用導(dǎo)致gc時間過長
it is not a good idea to rely on it because it runs unpredictably. 參考1
如何正確關(guān)閉流:https://javarevisited.blogspot.com/2014/10/right-way-to-close-inputstream-file-resource-in-java.html