java zip malformed-ag凯发k8国际
关于java解压文件的一些坑及经验分享
就在本周, 测试人员找到我说现上的需求文档(zip格式的)无法预览了, 让我帮忙看看怎么回事。
这个功能也并不是我做的, 于是我便先看看线上日志有没有什么错误,果不其然, 后台果然报错了。
java.lang.illegalargumentexception:malformed
at java.util.zip.zipcoder.tostring(zipcoder.tostring:58)
...
异常大致是这样,前台无法预览需求文档的原因是该zip文件解压失败了。
首先网上查了下这个异常的原因, 都说是因为编码的问题, 要求将utf-8改成gbk就可以了。
然后定位代码, 看到有一个方法:unzip()public static void unzip(file zipfile, string descdir) { try {
file pathfile = new file(descdir); if (!pathfile.exists()) {
pathfile.mkdirs();
}
zipfile zip = getzipfile(zipfile); for (enumeration entries = zip.entries(); entries.hasmoreelements(); ) {
zipentry entry = (zipentry) entries.nextelement();
string zipentryname = entry.getname(); if (stringutils.isnotblank(pre)) {
zipentryname = zipentryname.substring(pre.length());
}
inputstream in = zip.getinputstream(entry);
string outpath = (descdir "/" zipentryname).replaceall("\\*", "/");
; //判断路径是否存在,不存在则创建文件路径
file file = new file(outpath.substring(0, outpath.lastindexof('/'))); if (!file.exists()) {
file.mkdirs();
} //判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
if (new file(outpath).isdirectory()) { continue;
} //输出文件路径信息
log.info("解压文件的当前路径为:{}", outpath);
outputstream out = new fileoutputstream(outpath);
ioutils.copy(in, out);
in.close();
out.close();
}
zip.close();
log.info("******************解压完毕********************");
} catch (exception e) {
log.error("[unzip] 解压zip文件出错", e);
}
}private static zipfile getzipfile(file zipfile) throws exception {
zipfile zip = new zipfile(zipfile, charset.forname("utf-8"));
enumeration entries = zip.entries(); while (entries.hasmoreelements()) { try {
entries.nextelement();
zip.close();
zip = new zipfile(zipfile, charset.forname("utf-8")); return zip;
} catch (exception e) {
zip = new zipfile(zipfile, charset.forname("gbk")); return zip;
}
} return zip;
}
于是便将线上的zip文件down下来 然后本地调试下, 发现在第9行中抛出了异常, 如下代码:zipentry entry = (zipentry) entries.nextelement();
再由最开始的异常日志找到zipcoder中的58行:string tostring(byte[] ba, int length) {
charsetdecoder cd = decoder().reset(); int len = (int)(length * cd.maxcharsperbyte()); char[] ca = new char[len]; if (len == 0) return new string(ca); // utf-8 only for now. other arraydeocder only handles
// codingerroraction.replace mode. zipcoder uses
// report mode.
if (isutf8 && cd instanceof arraydecoder) { int clen = ((arraydecoder)cd).decode(ba, 0, length, ca); if (clen == -1) // malformed
throw new illegalargumentexception("malformed"); return new string(ca, 0, clen);
}
bytebuffer bb = bytebuffer.wrap(ba, 0, length);
charbuffer cb = charbuffer.wrap(ca);
coderresult cr = cd.decode(bb, cb, true); if (!cr.isunderflow()) throw new illegalargumentexception(cr.tostring());
cr = cd.flush(cb); if (!cr.isunderflow()) throw new illegalargumentexception(cr.tostring()); return new string(ca, 0, cb.position());
}
这里只有utf-8才会进入if逻辑才会抛错?果然如网上所说, 将编码格式改为gbk即可。
zipcoder这个类似src.zip包中的, 既然这里做了check当然会有它的道理, 单纯的改为gbk来解决这个bug显然是不合理的。
于是便要换种思路了, 线上有些zip是仍然可以预览的。 我将线上的zip文件解压后, 在自己电脑重新打个包(我用的是好压), 然后又运行了上述代码, 竟然解压成功?? 这是为什么? 于是上网上找了一下, 果然找到了答案:windows 压缩的时候使用的是系统的编码 gb2312,而 mac 系统默认的编码是 utf-8,于是出现了乱码。
最后去问了上传的同事, 他是在windows下用的winrar上传的(看来不同的解压工具还不同)。
好了, 问题基本定位到了, 这里就要想着怎么解决了。
又是一通找, 终于:apache commons-compress 解压 zip 文件是件很幸福的事,可以解决 zip 包中文件名有中文时跨平台的乱码问题,不管文件是在 windows 压缩的还是在 mac,linux 压缩的,解压后都没有再出现乱码问题了。
看到这里基本上问题就要解决了, 于是开始使用apache的commons-compress了, 下面直接上代码, 代码是基于上面代码进行改造的:
首先引入pom文件:
org.apache.commons
commons-compress
1.8.1public static void main(string[] args) throws exception{
string path = "c:\\users\\isuzu\\desktop\\test.zip";
unzip(new file(path), "d:\\data",);
}public static void unzip(file zipfile, string descdir) { try (ziparchiveinputstream inputstream = getzipfile(zipfile)) {
file pathfile = new file(descdir); if (!pathfile.exists()) {
pathfile.mkdirs();
}
ziparchiveentry entry = null; while ((entry = inputstream.getnextzipentry()) != null) { if (entry.isdirectory()) {
file directory = new file(descdir, entry.getname());
directory.mkdirs();
} else {
outputstream os = null; try {
os = new bufferedoutputstream(new fileoutputstream(new file(descdir, entry.getname()))); //输出文件路径信息
log.info("解压文件的当前路径为:{}", descdir entry.getname());
ioutils.copy(inputstream, os);
} finally {
ioutils.closequietly(os);
}
}
} final file[] files = pathfile.listfiles(); if (files != null && files.length == 1 && files[0].isdirectory()) { // 说明只有一个文件夹
fileutils.copydirectory(files[0], pathfile); //免得删除错误, 删除的文件必须在/data/demand/目录下。
boolean isvalid = files[0].getpath().contains("/data/www/"); if (isvalid) {
fileutils.forcedelete(files[0]);
}
}
log.info("******************解压完毕********************");
} catch (exception e) {
log.error("[unzip] 解压zip文件出错", e);
}
}private static ziparchiveinputstream getzipfile(file zipfile) throws exception { return new ziparchiveinputstream(new bufferedinputstream(new fileinputstream(zipfile)));
}
到了这里就大功告成了, 原先自己遇到这个问题时百度了一圈, ag凯发k8国际的解决方案大都是改编码格式为gbk, 但那也只是治标不治本的方法, 解压的坑就讲这么多, 后续有新的坑还会继续总结出来的。
总结
以上是ag凯发k8国际为你收集整理的java zip malformed_关于java解压文件的一些坑及经验分享(malformed异常)的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: java虚拟机调用linux_java虚
- 下一篇: java nep_java 9 揭秘(1