这里研究一下如何来判断文件的编码是否是UTF-8,关于这个问题网络上一般采用的是判断文件的BOM头,但是这种方法有个缺点,就是有一些工具,比如EditPlus,比如Java程序,做出来的UTF-8编码的文件是不会在文件内容的前面加上BOM头的,对于这种情况,网络上的这个办法就会检测失败。
在经过一些测试之后,研究了一个解决方案。
考虑如下文件输入流的代码,
FileInputStream fis = null;
InputStreamReader isr = null;
BufferedReader br = null;
File f = new File(fn);
fis = new FileInputStream(f);
isr = new InputStreamReader(fis, "UTF-8");
br = new BufferedReader(isr);
推测执行原理如下,(都是根据测试结果的猜测)
1。fis 根据文件的保存编码来采用不同的编码读取文件。读取结果为byte[]
2.isr设定的话,那么根据isr设定的编码来读取文件,如果不设定,那么编码采用系统默认编码 ansi(window-31j,shift_jis)
3。br.readline,将isr的结果组合为String,如果isr没有设定编码,那么组合String时采用的编码为系统默认编码 ansi(window-31j,shift_jis),如果isr设定了编码,那么采用isr设定好的编码。
4。new string(byte[],"encode") 根据指定编码生成string,如果不指定,采用系统默认编码。系统默认编码 ansi
5。string.getbyte("encode") 从String根据特定的编码取得byte[]
问题出在第1步,第一步fis因为读取文件的时候,调用的是native,也就是系统(windows系统)的东西,他用了系统的东西,系统的这个东西作了编码判断,但是因为他调用的是native的东西,这个判定结果没有返回给java,导致java里面isr,br没有办法跟fis协调一致,isr,br只能采用系统默认编码 ansi(window-31j,shift_jis),而不是采用fis的判定结果来读取文件。
这导致了,当文件使用ansi编码保存的时候,默认编码跟fis判定结果一致,不会出任何问题。
当文件使用了utf-8编码的时候,默认编码ansi,跟fis判定结果utf-8不一致,fis采用uft-8编码读取出文件内容,而后,br.readline采用系统默认编码把UTF-8编码对应的byte[]组合成了ansi编码对应的字符串,就产生了乱码。
我在网络以及java api里面查找了一下,没有找到判定文件保存编码的方法。推论:因为java是调用了native的方法来实际读取文件的,判定在native里面完成,但是没有把判定结果公开给我们程序员。
另有一个测试结果的推论,英文字符在任何编码下面读取出来的byte[]都是一样的。因为我们才用任何编码都不会出现英文字符乱码的问题,所以大多数时候这个判定对我们没有影响,这里不讨论特殊情况下因为这个原因造成的影响。
根据以上推论,考虑如下解决问题的思路,
1。通过fis来读取文件,这个时候读取来的byte[]根据文件的保存格式是不同的。fis会自动判断处理。
2。通过br来读取文件。代码示例如下:
private static void readTest(String fn){
BufferedReader br = null;
InputStreamReader isr = null;
FileInputStream fis = null;
try{
File f = new File(fn);
fis = new FileInputStream(f);
isr = new InputStreamReader(fis, "UTF-8");
br = new BufferedReader(isr);
String s = null;
while ((s = br.readLine()) != null) {
byte[] buf = s.getBytes("UTF-8");
for(int j=0; j<buf.length; j++){
System.out.println(buf[j]);
}
}
} catch(Exception e){
e.printStackTrace();
} finally{
try{
fis.close();
isr.close();
} catch(Exception e){
e.printStackTrace();
}
}
}
3。1,2的读取结果byte[]进行比较,如果相同,那么可以认为文件的保存格式为UTF-8(虽然存在全英文ansi保存的可能,但是这种状况认为是utf-8保存不会有影响),如果不同则不是UTF-8,考虑我们目前状况,那么不是UTF-8可以认为文件保存编码就是ANSI,如果不可以这么认为,其他编码类型也要做这个判断。因为英文字符在任何编码下面读取出来的byte[]都是一样的。所以这里有一个效率问题,必须文件内容全部比较,不能只比较一部分。
以上推测经测试有效,没有问题。
如果使用第三方开源代码common-io.jar的话,可以将以上思路简化为如下代码。
public boolean isUTF8(File file){
try {
byte[] buf = FileUtils.readFileToByteArray(file);
String filecCntent = FileUtils.readFileToString(file,"UTF-8");
if(filecCntent.equals(new String(buf,"UTF-8"))){
return true;
}
} catch (IOException e) {
// TODO 動生成された catch ブロック
e.printStackTrace();
}
return false;
}
这个判定有一个效率问题,在这个文章中采用的是读取整个文件,如果我们文件太大,会比较花时间。这种情况可以考虑按行来读取判定,某一行不一致就可以退出了。这样可以提高一些效率。
分享到:
相关推荐
一个判断文件为utf-8的java类,自己用有限状态机实现的,很好用的。
Recognize类判定指定文本文件为UTF-8还是GBK编码格式。
资源介绍:。判断给定缓冲区是否可能是UTF-8编码。windows7旗舰版notepad.exe代码。资源作者:。andyup。资源界面:。资源下载:。
Python 简单使用 pandas 读取excel 的 csv文件处理,支持utf-8和gbk编码自动识别。
Java判断文件的编码, 适用于utf-8和gbk码的判断。
它的类库很小,只有500K左右,利用该类库判定文本文件的代码如下(由于cpdetector的算法使用概率统计,所以结果并不是100%准确的,但是是迄今为止我见过
判断给定缓冲区是否可能是UTF-8编码。windows7旗舰版notepad.exe代码。 andyup
判断文件编码格式和批量将gbk转为utf-8,感觉还是判断的准确,不知道大家用的准确么?
将本程序放到文件目录下,然后执行,默认会将所有txt文件的编码格式修改为utf-8,可更改判断后缀名修改其他类型的文件。
(包括ANSI、UNICODE、UNICODE big endian、UTF-8)格式的文本文件 */ //核心算法:CStdioFileEx继承自CStdioFile, 覆盖CStdioFile的 BOOL ReadString(CString& rString)方法, // 根据不同文件编码特征,寻找文件...
易语言-判断文本编码是否为UTF-8格式
鉴于对多数系统来说,使用是更被广泛使用的utf8,所以判断是不是utf8格式显得很重要了。 下面是一个判断字符串是否为utf8的函数: bool is_str_utf8(const char* str) { unsigned int nBytes = 0;//UFT8可用1-6个...
选择文件夹后自动转换对应的文件编码为UTF-8,多语言代码转换时候经常会使用。部分类型的文件编码判断和转换会出错,请注意先备份文件后再转换进行测试。
判断上传的文件编码方式-支持各种编码方式,GB2312、utf-8、gbk、utf-16...
利用chardet,cpdetector包获取文件格式,并判断文件类型是否带BOM
以下是获取文件编码的一个类: using System; using System.IO; using System.Text; /// /// FileEncoding 的摘要说明 /// namespace FileEncoding { /// /// 获取文件的编码格式 /// public class Encoding...
判断字符编码格式代码,用C++编写的如何判断字符编码格式,UTF-8,ASCII等
Ruby 与编码 常见问题 * 乱码的问题 * Ruby 中 Unable to convert "\x89" from ASCII-8BIT to UTF8 *Incompatible character encodings: ASCII- 8BIT and UTF-8
该程序支持.c .h .cpp .hpp .bat .java等6种格式的文件编码转换,如果需要添加其他格式的文件,直接修改suffix的条件判断处的语句即可,压缩包中提供exe程序和python写的源码
java读写excel包括utf8转码为可识别汉字gbk,jxl方式读取excel,生成一个新的excel