java.util.zip.ZipInputStream和java.util.zip.ZipOutputStream压缩和解压带有中文名文件的ZIP包时,会报如下异常:
java.lang.IllegalArgumentException
at java.util.zip.ZipInputStream.getUTF8String(ZipInputStream.java:293)
at java.util.zip.ZipInputStream.readLOC(ZipInputStream.java:247)
at java.util.zip.ZipInputStream.getNextEntry(ZipInputStream.java:74)
at com.test.ZipTest.unZipAssetSouce(ZipTest.java:25)
at com.test.ZipTest.main(ZipTest.java:14)
原因是JDK自带的ZIP工具类,默认读取文件名采用的是UTF-8编码,而对于那些文件名以非UTF-8编码的文件将不能正确读入,如利用WinZip压缩的ZIP包将不能处理有中文名的文件,其采用的是ASCII编码的,而在开发中往往会遇到这样的问题,下面给出解决方案:
提取JDK内部几个处理ZIP相关的类,Deflater.java,DeflaterOutputStream.java,InflaterInputStream.java,ZipConstants.java,ZipEntry.java,ZipInputStram.java,然后自定义一个CompresszZipFile.java 读入ZIP文件,源码:
- import java.io.BufferedInputStream;
- import java.io.BufferedOutputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- public class CompresszZipFile {
- static final int BUFFER = 2048;
- /**
- * 读取ZIP文件,只适合于ZIP文件对于RAR文件无效,因为ZIP文件的压缩算法是公开的,而RAR不是
- * @version 1.0
- * @param zipfilepath:ZIP文件的路径,unzippath:要解压到的文件路径
- */
- public void ReadZip(String zipfilepath,String unzippath){
- try {
- BufferedOutputStream bos = null;
- //创建输入字节流
- FileInputStream fis = new FileInputStream(zipfilepath);
- //根据输入字节流创建输入字符流
- BufferedInputStream bis = new BufferedInputStream(fis);
- //根据字符流,创建ZIP文件输入流
- ZipInputStream zis = new ZipInputStream(bis);
- //zip文件条目,表示zip文件
- ZipEntry entry;
- //循环读取文件条目,只要不为空,就进行处理
- while((entry=zis.getNextEntry())!=null){
- System.out.println("===="+entry.getName());
- int count ;
- byte date[] = new byte[BUFFER];
- //如果条目是文件目录,则继续执行
- if(entry.isDirectory()){
- continue;
- }else{
- int begin = zipfilepath.lastIndexOf("\\")+1;
- int end = zipfilepath.lastIndexOf(".")+1;
- String zipRealName = zipfilepath.substring(begin,end);
- bos = new BufferedOutputStream(new FileOutputStream(this.getRealFileName(unzippath+"\\"+zipRealName,entry.getName())));
- while((count=zis.read(date))!=-1){
- bos.write(date,0,count);
- }
- bos.flush();bos.close();
- }
- }
- zis.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- private File getRealFileName(String zippath,String absFileName){
- String[] dirs = absFileName.split("/",absFileName.length());
- //创建文件对象
- File file = new File(zippath);
- if(dirs.length>1){
- for(int i=0;i<dirs.length-1;i++){
- //根据file抽象路径和dir路径字符串创建一个新的file对象,路径为文件的上一个目录
- file = new File(file,dirs[i]);
- }
- }
- if(!file.exists()){
- file.mkdirs();
- }
- file = new File(file,dirs[dirs.length-1]);
- return file;
- }
- }
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class CompresszZipFile {
static final int BUFFER = 2048;
/**
* 读取ZIP文件,只适合于ZIP文件对于RAR文件无效,因为ZIP文件的压缩算法是公开的,而RAR不是
* @version 1.0
* @param zipfilepath:ZIP文件的路径,unzippath:要解压到的文件路径
*/
public void ReadZip(String zipfilepath,String unzippath){
try {
BufferedOutputStream bos = null;
//创建输入字节流
FileInputStream fis = new FileInputStream(zipfilepath);
//根据输入字节流创建输入字符流
BufferedInputStream bis = new BufferedInputStream(fis);
//根据字符流,创建ZIP文件输入流
ZipInputStream zis = new ZipInputStream(bis);
//zip文件条目,表示zip文件
ZipEntry entry;
//循环读取文件条目,只要不为空,就进行处理
while((entry=zis.getNextEntry())!=null){
System.out.println("===="+entry.getName());
int count ;
byte date[] = new byte[BUFFER];
//如果条目是文件目录,则继续执行
if(entry.isDirectory()){
continue;
}else{
int begin = zipfilepath.lastIndexOf("\\")+1;
int end = zipfilepath.lastIndexOf(".")+1;
String zipRealName = zipfilepath.substring(begin,end);
bos = new BufferedOutputStream(new FileOutputStream(this.getRealFileName(unzippath+"\\"+zipRealName,entry.getName())));
while((count=zis.read(date))!=-1){
bos.write(date,0,count);
}
bos.flush();bos.close();
}
}
zis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private File getRealFileName(String zippath,String absFileName){
String[] dirs = absFileName.split("/",absFileName.length());
//创建文件对象
File file = new File(zippath);
if(dirs.length>1){
for(int i=0;i<dirs.length-1;i++){
//根据file抽象路径和dir路径字符串创建一个新的file对象,路径为文件的上一个目录
file = new File(file,dirs[i]);
}
}
if(!file.exists()){
file.mkdirs();
}
file = new File(file,dirs[dirs.length-1]);
return file;
}
}
然后建立一个测试类 ZipTest.java,源码:
- import com.zip.tool.CompresszZipFile;
- public class ZipTest {
- public static void main(String args[]){
- CompresszZipFile compress = new CompresszZipFile();
- compress.ReadZip("D:\\Android\\workspace\\Test\\word.zip", "D:\\test");
- }
- }
import com.zip.tool.CompresszZipFile;
public class ZipTest {
public static void main(String args[]){
CompresszZipFile compress = new CompresszZipFile();
compress.ReadZip("D:\\Android\\workspace\\Test\\word.zip", "D:\\test");
}
}
测试运行OK 。。。
为方便大家测试,将以上相关类打成一个jar包分享给大家!!(以上源码有些来源于网络)