2011年3月4日星期五

Java判定文件编码或文本流编码并直接输出

主要原理利用JCharDet猜测文本流 
JCharDet 是mozilla自动字符集探测算法代码的java移植,其官方主页为:http://jchardet.sourceforge.net/

网上找到的教程都是只探测编码,而一般的需求都是找到编码后,利用编码信息,把文本流或者文本再读取出来,可是问题来了,在探测编码后,JCharDet会读取一部分文本流了,不能再回过头去读文本了。可能的办法是再重新读取一次文件,或者再原来的其他操作得到一个新的InputStream,不过这样做总觉得不舒服。
其实可以利用BufferedInputStream的mark()和reset()方法(BufferedInputStream支持此操作):
mark用于标记当前位置;在读取一定数量的数据(小于readlimit的数据)后使用reset可以回到mark标记的位置。

测试代码如下:
public class Test {
public static void main(String[] args) throws Exception {
File file = new File("F:\\test.lrc");
BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
CharsetDetector charDect = new CharsetDetector();
String encode = charDect.detectChineseCharset(in, 5120);
System.out.println("侦测到的编码: " + encode);
BufferedReader reader = new BufferedReader(new InputStreamReader(in,
encode));
while (true) {
String line = reader.readLine();
if (line == null)
break;
System.out.println(line);
}
reader.close();
in.close();
}
}

CharsetDetector类的代码如下(附带注释):
public class CharsetDetector {

private boolean found = false;
private String result;
private int lang;

/**
* @param imp
*            文本流需要封装成BufferedInputStream
* @param readlimit
*            探测的时候,最多用到多少,读到这个limit的时候就reset回去,供以后文本读取的方法读取,
*            一般测试下来5120应该就能检测出编码了,再多可能对性能有影响,
*            如果readlimit为负数,说明只要检测编码,不需要为BufferedInputStream mark,
*            不用文本读取,直接关闭流就可以了
* @param defaultCharset
*            默认的编码
*/
public String detectChineseCharset(BufferedInputStream imp, int readlimit,
String defaultCharset) throws IOException {
if (defaultCharset == null)
defaultCharset = "UTF-8";
if (readlimit > 0)
imp.mark(readlimit);
lang = nsPSMDetector.CHINESE;
// Initalize the nsDetector() ;
nsDetector det = new nsDetector(lang);
// Set an observer...
// The Notify() will be called when a matching charset is found.

det.Init(new nsICharsetDetectionObserver() {

public void Notify(String charset) {
found = true;
result = charset;
}
});
byte[] buf = new byte[1024];
int readRemain = readlimit;
boolean isAscii = true;
while (true) {
int bufLength = 1024;
if (readRemain > 0 && readRemain < bufLength)
bufLength = readRemain;
int len = imp.read(buf, 0, bufLength);
if (len == -1)
break;
readRemain -= len;
if (readRemain <= 0)
break;
// Check if the stream is only ascii.
if (isAscii)
isAscii = det.isAscii(buf, len);
// DoIt if non-ascii and not done yet.
if (!isAscii) {
if (det.DoIt(buf, len, false))
break;
}
}
if (readlimit > 0)
imp.reset();
else
imp.close();
det.DataEnd();
if (isAscii) {
found = true;
return defaultCharset;
} else if (found) {
return result;
} else {
String[] pc = det.getProbableCharsets();
if (pc == null || pc.length == 0)
return defaultCharset;
else
return pc[0];
}
}
}

1 条评论:

xistkaelber 说...

네이트온 추가 하시면 온라인바카라 변경된 다파벳 주소를 확인하실수 있습니다. 새로가입하신모든신규회원님들은캐쉬백 VIP클럽의회원이되시며, 다른 VIP클럽을원하실경우에는이동하실수있습니다. 캐쉬백클럽회원님께서는더좋은조건으로캐쉬포인트환전률과라이브게임과슬롯게임에서의높은무제한캐쉬백비율, 그리고라이브바카라에서의높은배팅한도를제공합니다. 다파벳카지노에서는한국회원님들을위해국제간의송금거래가가능한머니부커스서비스외에도다파벳카지노가소지하고있는한국계좌로입출금이가능하도록계좌이체서비스를제공해드리고있습니다.

Swift Hash&Convert,写了第一个Mac小程序

README Swift Hash&Convert https://github.com/yaoxinghuo/SwiftHash Hash&Convert app for Mac, for develop use, written in ...