该使用哪个库?
截至本文撰写时,出现了三个库:
我不包括 Apache Any23,因为它在底层使用 ICU4j 3.4。
如何确定哪个检测到了正确的字符集(或尽可能接近)?
无法证明以上每个库检测到的字符集。但是,可以依次询问它们并对返回的响应进行评分。
如何对返回的响应进行评分?
可以为每个响应分配一个分数。响应得分越高,检测到的字符集的可信度就越高。这是一种简单的评分方法。您可以制定其他评分方法。
有样例代码吗?
这是一个完整的代码片段,实现了上述策略。
public static String guessEncoding(InputStream input) throws IOException {
long count = 0;
int n = 0, EOF = -1;
byte[] buffer = new byte[4096];
ByteArrayOutputStream output = new ByteArrayOutputStream();
while ((EOF != (n = input.read(buffer))) && (count <= Integer.MAX_VALUE)) {
output.write(buffer, 0, n);
count += n;
}
if (count > Integer.MAX_VALUE) {
throw new RuntimeException("Inputstream too large.");
}
byte[] data = output.toByteArray();
Map<String, int[]> encodingsScores = new HashMap<>();
updateEncodingsScores(encodingsScores, new CharsetToolkit(data).guessEncoding().displayName());
CharsetDetector charsetDetector = new CharsetDetector();
charsetDetector.setText(data);
charsetDetector.enableInputFilter(true);
CharsetMatch cm = charsetDetector.detect();
if (cm != null) {
updateEncodingsScores(encodingsScores, cm.getName());
}
UniversalDetector universalDetector = new UniversalDetector(null);
universalDetector.handleData(data, 0, data.length);
universalDetector.dataEnd();
String encodingName = universalDetector.getDetectedCharset();
if (encodingName != null) {
updateEncodingsScores(encodingsScores, encodingName);
}
Map.Entry<String, int[]> maxEntry = null;
for (Map.Entry<String, int[]> e : encodingsScores.entrySet()) {
if (maxEntry == null || (e.getValue()[0] > maxEntry.getValue()[0])) {
maxEntry = e;
}
}
String winningEncoding = maxEntry.getKey();
return winningEncoding;
}
private static void updateEncodingsScores(Map<String, int[]> encodingsScores, String encoding) {
String encodingName = encoding.toLowerCase();
int[] encodingScore = encodingsScores.get(encodingName);
if (encodingScore == null) {
encodingsScores.put(encodingName, new int[] { 1 });
} else {
encodingScore[0]++;
}
}
private static void dumpEncodingsScores(Map<String, int[]> encodingsScores) {
System.out.println(toString(encodingsScores));
}
private static String toString(Map<String, int[]> encodingsScores) {
String GLUE = ", ";
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, int[]> e : encodingsScores.entrySet()) {
sb.append(e.getKey() + ":" + e.getValue()[0] + GLUE);
}
int len = sb.length();
sb.delete(len - GLUE.length(), len);
return "{ " + sb.toString() + " }";
}
改进:
guessEncoding
方法会完整读取输入流。对于大型输入流,这可能是一个问题。所有这些库都将读取整个输入流。这将意味着检测字符集需要大量时间消耗。
可以将初始数据加载限制为几个字节,并只对这些少量字节执行字符集检测。
Reader.getEncoding
返回读取器设置的编码,而在您的情况下,这是默认编码。 - Karol SSystem.getProperty("file.encoding")
it returns string. ex -FileInputStream fis = new FileInputStream(path); String encoding = System.getProperty("fis.encoding");
- Sathvik