对于Java本身,很多功能都会遭到大家的质疑,但是真的是Java本身做的不好么? 我想应该不是的。
对于Java自身自带的压缩文件操作来说,最大的弊端应该就是对中文的不支持,所以很多人都会去选择apache公司提供的。然而apache公司提供的同样也有语言问题。但Java自身的就不会。
在我去网上找过相关的资料,发现除了使用apache的之外,还有去修改源码,而修改源码这种方式,对于很多新手来说,是非常头痛的事情。那就没有解决方式了么?
在最近做项目的时候,正好就用到这个压缩文件的操作,倒是解决了个别语言乱码的问题。(当然,肯定不是通过修改源码,也不是通过apache)。
因为我用的是jdk1.7的,所以我就用1.7的来说。
先说一下,我当时要做的功能:
我的功能能就是用户批量上传一大堆的压缩包,然后我通过后台再开一个线程去解析上传的压缩文件,在不解压的情况下,将压缩包中的数据读出来,并将压缩包中需要上传的文件上传到服务器。
功能不麻烦,但唯一不能确定的是压缩包中的文件是否是中文命名,如果是中文命名,用java自身自带的zipInputStream就会报错。
通过查看源码,我发现在ZipInputStream中,有两个构造方法:
public ZipInputStream(InputStream in) { this(in, StandardCharsets.UTF_8); } public ZipInputStream(InputStream in, Charset charset) { super(new PushbackInputStream(in, 512), new Inflater(true), 512); usesDefaultInflater = true; if(in == null) { throw new NullPointerException("in is null"); } if (charset == null) throw new NullPointerException("charset is null"); this.zc = ZipCoder.get(charset); }
期初我用的是第一个,也就是只传了一个inputStream进去。但是当报错失败的时候,发现这个构造方法,默认我们的编码为"UTF-8"。那期初我就很费解,我从页面端传递,到数据库所有都统一是"UTF-8"。并且,我的其他上传用"UTF-8"也成功解决了中文问题,那为何这个就不可以呢?
在我通过使用第二个构造方法时通过:
ZipInputStream zip = new ZipInputStream(in,StandardCharsets.UTF-8);
的方式将UTF-8给传入进去,结果一样的, 当然,这个是意料之中的。(StandardCharsets是Java自身提供的)。
那我的想法是,既然有提供可以自定义编码,那我一个个尝试一下看看?
期初,我是想通过设置为"GBK"的方式,
但是,我发现StandardCharsets这个类提供的编码很少:
public static final Charset US_ASCII = Charset.forName("US-ASCII"); public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); public static final Charset UTF_8 = Charset.forName("UTF-8"); public static final Charset UTF_16BE = Charset.forName("UTF-16BE"); public static final Charset UTF_16LE = Charset.forName("UTF-16LE"); public static final Charset UTF_16 = Charset.forName("UTF-16");
这让我很失望,因为这里面,我能联系到解决中文的方式只有UTF-8。
不过,我很好奇,因为我想不透为何Java只给我们提供考了这几种编码?难道是考虑不周详?
有这个想法后,我就想试试看Java给我们留这几个编码的用意。
"ASCII"码很容易理解,我也感觉也许会把这个流默认读成"ASCII"码呢?
但是,试过之后发现不行,仍然过不了,依然报错。
那就一个一个试一下看看呗。
奇迹来了,在我使用"ISO-8859-1"的时候居然通过了。
然后,我将通过"ISO-8859-1"转化过来的乱码再次转换,以恢复到以前的汉字状态,这样我就能知道zipInputStream流默认的是什么编码了
在我通过new String的方式来转化的时候,发现只有在转化为"GBK"的时候才能显示原来的汉字状态。
那我就大概明白这个问题了。
然后,我就修改自己的代码:
zipFile = new ZipFile(filePath,StandardCharsets.ISO_8859_1); InputStream in = new BufferedInputStream(new FileInputStream(filePath)); //转化为iso_8859_1,保证zip.getNextEntry()能够通过 ZipInputStream zip = new ZipInputStream(in,StandardCharsets.ISO_8859_1); ZipEntry zipEntry; while ((zipEntry = zip.getNextEntry()) != null) { //判断是否为目录条目,此处不用操作。 if(zipEntry.isDirectory()){ }else{ //获取文件名(此文件名会包含路径) String fileName1 = zipEntry.getName(); //此文件名是真正的文件名 String fileName2 = getFileNameByFilePath(fileName1); System.out.println(fileName2.toString()); } }
将流转为”ISO-8859-1“后,让其顺利通过zip.getNextEntry(),
如果要保存压缩包中文件的真实名字的话,就可以通过
byte[] b = fileName2.getBytes("ISO_8859_1"); new String(b,"GBK");
来获取原来的名字。