Java 杂谈

java获得stream流或文件的编码格式

2018-10-20  本文已影响0人  醉里挑灯看剑422

需求

直接上代码

String url = "http://xxx.xxx/xx.txt"; //需要从网络读取的文件
Inputstream is = new URL(url).openStream;
//接下来,把Inputstream读成String

然而该stream的编码未知,且不同文件编码不同。默认使用utf-8或gb2312都会造成部分结果乱码。

solution

//BufferedInputStream支持mark,可以重复读取stream,避免网络请求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);

解释

背景知识

  1. 字符编码 http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

心路历程

  1. 首先尝试stream或file有没有方法直接getEncoding,得到结论:
    You cannot determine the encoding of a arbitrary byte stream. 如果理解了字符编码背景知识,这个应该很容易理解参考

  2. 那么如何得到一个流的编码,还是有人做出了工具:

<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函数名很灵性。原理是读一遍流,根据各种编码特点推断输入流的编码。既然是guess就不是100%准的,不过实用效果不错。感兴趣的同学可以深入一下。

  1. guessEncoding已经把stream读过一遍了,直接转string得到空字符串。又不想再发一次网络请求重新获取。然后,发现BufferedInputStream支持mark/reset, 重复读取。finished,完美。
    参考:http://zhangbo-peipei-163-com.iteye.com/blog/2022460

副产品:IO流的关闭问题

FIleInputStream的finalize方法会调用close(),即gc时会帮你关闭io,but,并不建议这样做。理由:

  1. 资源没有被及时释放;
  2. finalize方法调用导致gc时间过长

it is not a good idea to rely on it because it runs unpredictably. 参考1

如何正确关闭流:https://javarevisited.blogspot.com/2014/10/right-way-to-close-inputstream-file-resource-in-java.html

上一篇下一篇

猜你喜欢

热点阅读