`
hyhyhy108
  • 浏览: 5345 次
  • 性别: Icon_minigender_1
  • 来自: 成都
文章分类
社区版块
存档分类
最新评论

java获取文件的编码格式

    博客分类:
  • java
 
阅读更多

最近的这个项目中需要对文件的编码格式进行处理,并统一转换为UTF-8格式,所以对文件的编码格式进行了一些探讨,但是在探讨的过程中发现使用java来处理文件的编码格式确实是一件比较头疼的问题,因为不能完全的获取到正确的编码格式,因为一部分文件具有头文件,我们可以根据这些头文件来判断文件格式,但是另一部分却是不存在头文件的,这样的话可能会导致获取文件格式出错,之前我们就是使用的文件头去判断的文件格式,代码如下:


public String getCharset(File file) {
String charset = "GBK";
byte[] first3Bytes = new byte[3];
boolean checked = false;
BufferedInputStream bis = null;

try {
bis = new BufferedInputStream(
new FileInputStream(file));
bis.mark(0);
int read = bis.read(first3Bytes, 0, 3);
if (read == -1)
return charset;
if (first3Bytes[0] == (byte) 0xFF && first3Bytes[1] == (byte) 0xFE) {
charset = "UTF-16LE";
checked = true;
} else if (first3Bytes[0] == (byte) 0xFE
&& first3Bytes[1] == (byte) 0xFF) {
charset = "UTF-16BE";
checked = true;
} else if (first3Bytes[0] == (byte) 0xEF
&& first3Bytes[1] == (byte) 0xBB
&& first3Bytes[2] == (byte) 0xBF) {
charset = this.encode_utf8;
checked = true;
}
bis.reset();
if (!checked) {
// int len = 0;
int loc = 0;

while ((read = bis.read()) != -1) {
loc++;
if (read >= 0xF0)
break;
if (0x80 <= read && read <= 0xBF) // 单独出现BF以下的,也算是GBK
break;
if (0xC0 <= read && read <= 0xDF) {
read = bis.read();
if (0x80 <= read && read <= 0xBF) // 双字节 (0xC0 - 0xDF)
// (0x80
// - 0xBF),也可能在GB编码内
continue;
else
break;
} else if (0xE0 <= read && read <= 0xEF) {// 也有可能出错,但是几率较小
read = bis.read();
if (0x80 <= read && read <= 0xBF) {
read = bis.read();
if (0x80 <= read && read <= 0xBF) {
charset = this.encode_utf8;
break;
} else
break;
} else
break;
}
}
}
} catch (Exception e) {
log.error("Obtaining file format failed",e);//获取文件格式失败
} finally {
try {
if (null != bis) {
bis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}

return charset;
}


但是遇到不是UTF-8格式的就不能处理了,而且当遇到没有BOM头的utf-8的时候也无法解决,且担心当没有头文件的文件的前几个字节与问价一致的时候,可能会判断错误问价的格式,后来我使用了网上所说的第三方包:cpdetector_1.0.7.jar,使用了这个第三方包,代码如下

CodepageDetectorProxy detector = CodepageDetectorProxy.getInstance();
detector.add(new ParsingDetector(false));
detector.add(JChardetFacade.getInstance());
detector.add(ASCIIDetector.getInstance());
detector.add(UnicodeDetector.getInstance());
Charset charset = null;
       try {
           charset = detector.detectCodepage(file.toURI().toURL());

       } catch (Exception ex) {
          log.error("Carest File error!");
       }


过了一段时间之后就发现问题了,使用这个后不但获取文件格式的时间超长(特别对比较大的文件来说),而且对于Unicode的编码格式也不是很支持,只要汉字中出现了"的都"等汉子之后解析的文件格式就完全错误,导致乱码了.而且时间太长导致了性能测试完全过不了,最后经过商讨订下了另一个方案,因为系统是部署在Liunx系统上的,所以决定使用liunx系统的file命令,这样时间不但比较短,且也比较准备,虽然不能完全解析所有的文件格式,但是文本文档的默认的4种已经完全能够支持了,当然如果使用了Editplus或者UE等高级浏览器,然后另存为一些格式也是无法解析的,所以这个是很痛苦的,不过已经能够支持文本编辑器的四种也满足了我们要求了,使用liunx系统命令操作如下

String command = "file " + file.getAbsolutePath();
Process proc = Runtime.getRuntime().exec(command);
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String code = br.readLine();
不过liunx系统也不是能获得所有的编码格式的,当你文件内容以&开头它可能也会解析错误的,这个的话可能要想想其他办法了,不过我们项目中的内容是绝对不会以&开头的.所以没有什么问题.

以上就是我在处理java获取文件编码格式所遇到的问题,还是要感慨一下java对文件编码格式的支持确实有点伤啊,

不过在这里还遇到可一个问题,就是取出文件的第一行数据然后判断是否为纯数字,然后我当然使用的是正则表达式的,不过这里却遇到一个问题,就是无论怎么验证一直是false,后来追了很久的代码才发现,原来正则表达式也是按照二进制的ascii嘛去匹配的,但是取出文本的第一行却发现String 的getBytes之后却获取到了它的头文件,也就是前三个字节全是负数,这个只去掉前三个字节再判断就OK了,还有使用file命令判断文件格式的话,如果是windows传上去的文件名中拥有空格这些,回导致你的命令执行不正确,因为linux上空格需要使用/转义,建议你们上传后修改为没有特殊字符的文件名.





这些就是在项目中的编码格式所遇到的困难和处理困难,如果有更好的处理方法的朋友,欢迎你告诉我,谢谢.

当然我也附上了第三方包所需要的的jar包,需要的朋友可以下载

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics