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) {
BufferedInputStream bis = null;
if (is instanceof BufferedInputStream) {
bis = (BufferedInputStream) is;
} else {
bis = new BufferedInputStream(is);
}
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(bis, Integer.MAX_VALUE);
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
}
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);
}
String charsetName = "GBK";
if (charset != null) {
if (charset.name().equals("US-ASCII")) {
charsetName = "ISO_8859_1";
} else {
charsetName = charset.name();
}
}
return charsetName;
}
}