美文网首页Java 杂谈
java获得stream流或文件的编码格式

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

作者: 醉里挑灯看剑422 | 来源:发表于2018-10-20 15:39 被阅读0次

    需求

    直接上代码

    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

    相关文章

      网友评论

        本文标题:java获得stream流或文件的编码格式

        本文链接:https://www.haomeiwen.com/subject/wdxmzftx.html