java 判斷文件編碼格式(支持zip)

java 判斷文件編碼格式(支持zip)

前言:

    最近在工作過程中遇到了這樣的問題: 通過文件上傳,需要導入zip包中的文件信息。
由於使用的是apache的ant.jar中的ZipFile類、ZipEntry類。由於目前該工具類並不能判斷zip中每個文件的具體的編碼,
導致解析時出現中文亂碼。通過查找資料發現借鑑使用第三方工具cpDetector解決。因此在此做個記錄。
    若想實現更復雜的文件編碼檢測,可以使用一個開源項目cpdetector,
    網址: http://cpdetector.sourceforge.net
它的類庫很小,只有500K左右,cpDetector是基於統計學原理的,不保證完全正確,利用該類庫判定文本文件的代碼如下:

準備條件

- 需要的jar包:cpdetector_1.0.10.jar、antlr-2.7.4.jar、chardet-1.0.jar、jargs-1.0.jar
- 源碼:cpdetector_1.0.10_binary.zip
- 相關資料:https://www.cnblogs.com/king1302217/p/4003060.html 

具體實現

    在此摸索過程中遇到的問題:  查找了網上的參考例子,但是幾乎所有的都是直接處理針對File對象的處理。
沒有針對zip文件的相關處理邏輯。並且由於apache的ZipFile 、 以及它內部的文件對象ZipEntry不能使用url方式。
於是查看底層實現代碼發現可以用此: 
    **charset = detector.detectCodepage(bis, Integer.MAX_VALUE);// zip 判斷的關鍵代碼**

注意:
    直接使用zipFile.getInputStream(zipEntry) 得到的inputStream流不支持mark()方法。
    但是cpdetector底層需要用此方法.後來查找發現底層其實有類似場景的特殊處理:
    若是不支持mark()則可以把inputStream包裝成支持的BufferedInputStream即可。如下:

這裏寫圖片描述

具體代碼如下:


import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.Charset;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import info.monitorenter.cpdetector.io.ASCIIDetector;
import info.monitorenter.cpdetector.io.CodepageDetectorProxy;
import info.monitorenter.cpdetector.io.JChardetFacade;
import info.monitorenter.cpdetector.io.ParsingDetector;
import info.monitorenter.cpdetector.io.UnicodeDetector;
/**
 * 1、cpDetector內置了一些常用的探測實現類,這些探測實現類的實例可以通過add方法加進來,
 *    ParsingDetector、 JChardetFacade、ASCIIDetector、UnicodeDetector. 
 * 2、detector按照“誰最先返回非空的探測結果,就以該結果爲準”的原則. 
 * 3、cpDetector是基於統計學原理的,不保證完全正確.
 */
public class FileCharsetDetector {
    private static final Logger logger = LoggerFactory.getLogger(FileCharsetDetector.class);

    /**
     * 利用第三方開源包cpdetector獲取文件編碼格式.
     * 
     * @param is
     *            InputStream 輸入流
     * @return
     */
    public static String getFileEncode(InputStream is) {
        //    begin     此段爲zip格式文件的處理關鍵
        BufferedInputStream bis = null;
        if (is instanceof BufferedInputStream) {
            bis = (BufferedInputStream) is;
        } else {
            bis = new BufferedInputStream(is);
        }
        //   end

        CodepageDetectorProxy detector = CodepageDetectorProxy.getInstance();

        detector.add(new ParsingDetector(false));
        detector.add(UnicodeDetector.getInstance());
        detector.add(JChardetFacade.getInstance());// 內部引用了 chardet.jar的類
        detector.add(ASCIIDetector.getInstance());

        Charset charset = null;
        try {
            charset = detector.detectCodepage(bis, Integer.MAX_VALUE);// zip 判斷的關鍵代碼
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }

        // 默認爲GBK
        String charsetName = "GBK";
        if (charset != null) {
            if (charset.name().equals("US-ASCII")) {
                charsetName = "ISO_8859_1";
            } else {
                charsetName = charset.name();
            }
        }
        return charsetName;
    }


    public static String getFileEncode(File  file) {
        CodepageDetectorProxy detector = CodepageDetectorProxy.getInstance();

        detector.add(new ParsingDetector(false));
        detector.add(UnicodeDetector.getInstance());
        detector.add(JChardetFacade.getInstance());
        detector.add(ASCIIDetector.getInstance());

        Charset charset = null;
        try {
            charset = detector.detectCodepage(file.toURI().toURL());
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } 

        // 默認爲GBK
        String charsetName = "GBK";
        if (charset != null) {
            if (charset.name().equals("US-ASCII")) {
                charsetName = "ISO_8859_1";
            } else {
                charsetName = charset.name();
            }
        }
        return charsetName;
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章