zip解压中文乱码解决与使用ant实现zip解压缩
来源:互联网 发布:淘宝哪些鞋店 编辑:程序博客网 时间:2024/05/01 10:12
缘由:
java对於文字的编码是以unicode为基础,因此,若是以ZipInputStream及ZipOutputStream来处理压缩及解压缩的工作,碰到中文档名或路径,那当然是以unicode来处理罗!
但是,现在市面上的压缩及解压缩软体,例如winzip,却是不支援unicode的,一碰到档名以unicode编码的档案,它就不处理。
那要如何才能做出让winzip能够处理的压缩档呢?
那要如何才能做出让winzip能够处理的压缩档呢?
有两种方式:
一种是使用apache的ant实现zip解压缩,另一种是修改jdk自带zip工具类的源码
因为ant内部是多线程读取文件,解压的文件虽然是乱序的,但是效率明显比jdk的zip方式高很多。推荐使用ant的zip实现。
第一种使用ant实现的zip解压缩,其中解压的乱码注意使用
public void unZip(String unZipFileName,String outputPath) 其中
this.zipFile = new ZipFile(unZipFileName, "GB18030");是解决中文名乱码的关键。
- <span style="font-size: 14px;">import java.io.*;
- import org.apache.tools.zip.*;
- import java.util.Enumeration;
- /**
- *<p>
- * <b>功能:zip压缩、解压(支持中文文件名)</b>
- *<p>
- * 说明:使用Apache Ant提供的zip工具org.apache.tools.zip实现zip压缩和解压功能.
- * 解决了由于java.util.zip包不支持汉字的问题。
- *
- * @author Winty
- * @modifier vernon.zheng
- */
- public class AntZip {
- private ZipFile zipFile;
- private ZipOutputStream zipOut; // 压缩Zip
- private ZipEntry zipEntry;
- private static int bufSize; // size of bytes
- private byte[] buf;
- private int readedBytes;
- // 用于压缩中。要去除的绝对父路路径,目的是将绝对路径变成相对路径。
- private String deleteAbsoluteParent;
- /**
- *构造方法。默认缓冲区大小为512字节。
- */
- public AntZip() {
- this(512);
- }
- /**
- *构造方法。
- *
- * @param bufSize
- * 指定压缩或解压时的缓冲区大小
- */
- public AntZip(int bufSize) {
- this.bufSize = bufSize;
- this.buf = new byte[this.bufSize];
- deleteAbsoluteParent = null;
- }
- /**
- *压缩文件夹内的所有文件和目录。
- *
- * @param zipDirectory
- * 需要压缩的文件夹名
- */
- public void doZip(String zipDirectory) {
- File zipDir = new File(zipDirectory);
- doZip(new File[] { zipDir }, zipDir.getName());
- }
- /**
- *压缩多个文件或目录。可以指定多个单独的文件或目录。而 <code>doZip(String zipDirectory)</code>
- * 则直接压缩整个文件夹。
- *
- * @param files
- * 要压缩的文件或目录组成的<code>File</code>数组。
- *@param zipFileName
- * 压缩后的zip文件名,如果后缀不是".zip", 自动添加后缀".zip"。
- */
- public void doZip(File[] files, String zipFileName) {
- // 未指定压缩文件名,默认为"ZipFile"
- if (zipFileName == null || zipFileName.equals(""))
- zipFileName = "ZipFile";
- // 添加".zip"后缀
- if (!zipFileName.endsWith(".zip"))
- zipFileName += ".zip";
- try {
- this.zipOut = new ZipOutputStream(new BufferedOutputStream(
- new FileOutputStream(zipFileName)));
- compressFiles(files, this.zipOut, true);
- this.zipOut.close();
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- }
- /**
- *压缩文件和目录。由doZip()调用
- *
- * @param files
- * 要压缩的文件
- *@param zipOut
- * zip输出流
- *@param isAbsolute
- * 是否是要去除的绝对路径的根路径。因为compressFiles()
- * 会递归地被调用,所以只用deleteAbsoluteParent不行。必须用isAbsolute来指明
- * compressFiles()是第一次调用,而不是后续的递归调用。即如果要压缩的路径是
- * E:\temp,那么第一次调用时,isAbsolute=true,则deleteAbsoluteParent会记录
- * 要删除的路径就是E:\ ,当压缩子目录E:\temp\folder时,isAbsolute=false,
- * 再递归调用compressFiles()时,deleteAbsoluteParent仍然是E:\ 。从而保证了
- * 将E:\temp及其子目录均正确地转化为相对目录。这样压缩才不会出错。不然绝对 路径E:\也会被写入到压缩文件中去。
- */
- private void compressFiles(File[] files, ZipOutputStream zipOut,
- boolean isAbsolute) throws IOException {
- for (File file : files) {
- if (file == null)
- continue; // 空的文件对象
- // 删除绝对父路径
- if (file.isAbsolute()) {
- if (isAbsolute) {
- deleteAbsoluteParent = file.getParentFile()
- .getAbsolutePath();
- deleteAbsoluteParent = appendSeparator(deleteAbsoluteParent);
- }
- } else
- deleteAbsoluteParent = "";
- if (file.isDirectory()) {// 是目录
- compressFolder(file, zipOut);
- } else {// 是文件
- compressFile(file, zipOut);
- }
- }
- }
- /**
- *压缩文件或空目录。由compressFiles()调用。
- *
- * @param file
- * 需要压缩的文件
- *@param zipOut
- * zip输出流
- */
- public void compressFile(File file, ZipOutputStream zipOut)
- throws IOException {
- String fileName = file.toString();
- /* 去除绝对父路径。 */
- if (file.isAbsolute())
- fileName = fileName.substring(deleteAbsoluteParent.length());
- if (fileName == null || fileName == "")
- return;
- /*
- * 因为是空目录,所以要在结尾加一个"/"。 不然就会被当作是空文件。 ZipEntry的isDirectory()方法中,目录以"/"结尾.
- * org.apache.tools.zip.ZipEntry : public boolean isDirectory() { return
- * getName().endsWith("/"); }
- */
- if (file.isDirectory())
- fileName = fileName + "/";// 此处不能用"\\"
- zipOut.putNextEntry(new ZipEntry(fileName));
- // 如果是文件则需读;如果是空目录则无需读,直接转到zipOut.closeEntry()。
- if (file.isFile()) {
- FileInputStream fileIn = new FileInputStream(file);
- while ((this.readedBytes = fileIn.read(this.buf)) > 0) {
- zipOut.write(this.buf, 0, this.readedBytes);
- }
- fileIn.close();
- }
- zipOut.closeEntry();
- }
- /**
- *递归完成目录文件读取。由compressFiles()调用。
- *
- * @param dir
- * 需要处理的文件对象
- *@param zipOut
- * zip输出流
- */
- private void compressFolder(File dir, ZipOutputStream zipOut)
- throws IOException {
- File[] files = dir.listFiles();
- if (files.length == 0)// 如果目录为空,则单独压缩空目录。
- compressFile(dir, zipOut);
- else
- // 如果目录不为空,则分别处理目录和文件.
- compressFiles(files, zipOut, false);
- }
- /**
- *解压指定zip文件。
- *
- * @param unZipFileName
- * 需要解压的zip文件名
- */
- public void unZip(String unZipFileName) {
- FileOutputStream fileOut;
- File file;
- InputStream inputStream;
- try {
- this.zipFile = new ZipFile(unZipFileName);
- for (Enumeration entries = this.zipFile.getEntries(); entries
- .hasMoreElements();) {
- ZipEntry entry = (ZipEntry) entries.nextElement();
- file = new File(entry.getName());
- if (entry.isDirectory()) {// 是目录,则创建之
- file.mkdirs();
- } else {// 是文件
- // 如果指定文件的父目录不存在,则创建之.
- File parent = file.getParentFile();
- if (parent != null && !parent.exists()) {
- parent.mkdirs();
- }
- inputStream = zipFile.getInputStream(entry);
- fileOut = new FileOutputStream(file);
- while ((this.readedBytes = inputStream.read(this.buf)) > 0) {
- fileOut.write(this.buf, 0, this.readedBytes);
- }
- fileOut.close();
- inputStream.close();
- }
- }
- this.zipFile.close();
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- }
- /**
- *解压指定zip文件。其中"GB18030"解决中文乱码
- *
- * @param unZipFileName
- * 需要解压的zip文件名
- * @param outputPath
- * 输出路径
- */
- public void unZip(String unZipFileName,String outputPath) {
- FileOutputStream fileOut;
- File file;
- InputStream inputStream;
- try {
- this.zipFile = new ZipFile(unZipFileName, "GB18030");
- for (Enumeration entries = this.zipFile.getEntries(); entries
- .hasMoreElements();) {
- ZipEntry entry = (ZipEntry) entries.nextElement();
- file = new File(outputPath+entry.getName());
- if (entry.isDirectory()) {// 是目录,则创建之
- file.mkdirs();
- } else {// 是文件
- // 如果指定文件的父目录不存在,则创建之.
- File parent = file.getParentFile();
- if (parent != null && !parent.exists()) {
- parent.mkdirs();
- }
- inputStream = zipFile.getInputStream(entry);
- fileOut = new FileOutputStream(file);
- while ((this.readedBytes = inputStream.read(this.buf)) > 0) {
- fileOut.write(this.buf, 0, this.readedBytes);
- }
- fileOut.close();
- inputStream.close();
- }
- }
- this.zipFile.close();
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- }
- /**
- *给文件路径或目录结尾添加File.separator
- *
- * @param fileName
- * 需要添加路径分割符的路径
- *@return 如果路径已经有分割符,则原样返回,否则添加分割符后返回。
- */
- private String appendSeparator(String path) {
- if (!path.endsWith(File.separator))
- path += File.separator;
- return path;
- }
- /**
- *解压指定zip文件。
- *
- * @param unZipFile
- * 需要解压的zip文件对象
- */
- public void unZip(File unZipFile) {
- unZip(unZipFile.toString());
- }
- /**
- *设置压缩或解压时缓冲区大小。
- *
- * @param bufSize
- * 缓冲区大小
- */
- public void setBufSize(int bufSize) {
- this.bufSize = bufSize;
- }
- // 主函数,用于测试AntZip类
- /*
- * public static void main(String[] args)throws Exception{
- * if(args.length>=2){ AntZip zip = new AntZip();
- *
- * if(args[0].equals("-zip")){ //将后续参数全部转化为File对象 File[] files = new File[
- * args.length - 1]; for(int i = 0;i < args.length - 1; i++){ files = new
- * File(args[i + 1]); }
- *
- * //将第一个文件名作为zip文件名 zip.doZip(files , files[0].getName());
- *
- * return ; } else if(args[0].equals("-unzip")){ zip.unZip(args[1]); return
- * ; } }
- *
- * System.out.println("Usage:");
- * System.out.println("压缩:java AntZip -zip [directoryName | fileName]... ");
- * System.out.println("解压:java AntZip -unzip fileName.zip"); }
- */
- }</span>
第二种 从修改ZipInputStream及ZipOutputStream对於档名的编码方式来着手了。
我们可以从jdk的src.zip取得ZipInputStream及ZipOutputStream的原始码来加以修改:
一、ZipOutputStream.java
1.从jdk的src.zip取得ZipOutputStream.java原始码,另存新档存到c:/java/util/zip这个资料夹里,档名改为CZipOutputStream.java。
2.开始修改原始码,将class名称改为CZipOutputStream
3.建构式也必须更改为CZipOutputStream
4.新增member,这个member记录编码方式
private String encoding="UTF-8";
5.再新增一个建构式(这个建构式可以让这个class在new的时候,设定档名的编码)
- <span style="font-size: 18px;"> </span><span style="font-size: 14px;">public CZipOutputStream(OutputStream out,String encoding) {
- super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
- usesDefaultDeflater = true;
- this.encoding=encoding;
- } </span>
6.找到byte[] nameBytes = getUTF8Bytes(e.name);(有二个地方),将它修改如下:
- <span style="font-size: 14px;"> byte[] nameBytes = null;
- try
- {
- if (this.encoding.toUpperCase().equals("UTF-8"))
- nameBytes =getUTF8Bytes(e.name);
- else
- nameBytes= e.name.getBytes(this.encoding);
- }
- catch(Exception byteE)
- {
- nameBytes=getUTF8Bytes(e.name);
- } </span>
7.将档案储存在c:/java/util/zip这个资料夹内,请记得一定要有这个路径结构,
才能把CZipOutputStream.class放在正确的package结构里
二、ZipInputStream.java
1.从jdk的src.zip取得ZipInputStream.java原始码,另存新档存到c:/java/util/zip这个资料夹里,档名改为CZipInputStream.java。
2.开始修改原始码,将class名称改为CZipInputStream
3.建构式也必须更改为CZipInputStream
4.新增member,这个member记录编码方式
private String encoding="UTF-8";
5.再新增一个建构式如下(这个建构式可以让这个class在new的时候,设定档名的编码)
- <span style="font-size: 14px;">public CZipInputStream(InputStream in,String encoding) {
- super(new PushbackInputStream(in,512),new Inflater(true),512);
- usesDefaultInflater = true;
- if(in == null) {
- throw new NullPointerException("in is null");
- }
- this.encoding=encoding;
- } </span>
6.找到ZipEntry e = createZipEntry(getUTF8String(b, 0, len));这一行,将它改成如下:
- <span style="font-size: 14px;">ZipEntry e=null;
- try
- {
- if (this.encoding.toUpperCase().equals("UTF-8"))
- e=createZipEntry(getUTF8String(b, 0, len));
- else
- e=createZipEntry(new String(b,0,len,this.encoding));
- }
- catch(Exception byteE)
- {
- e=createZipEntry(getUTF8String(b, 0, len));
- } </span>
7.将档案储存在c:/java/util/zip这个资料夹内,请记得一定要有这个路径结构,才能把CZipInputStream.class放在正确的package结构里
以上两个档案储存後compile产生CZipOutputStream.class及CZipInputStream.class,使用winzip开启[java_home]/jre/lib/rt.jar这个档案,将CZipOutputStream.class及CZipInputStream.class加进去,记得「Save full path info」一定要打勾。
以後当压缩及解压缩时有中文档名及路径的问题时,就可以指定编码方式来处理了。
以「压缩与解压缩(1)」为例:
- <span style="font-size: 14px;">CZipOutputStream zos=new CZipOutputStream(OutputStream os,String encoding);
- CZipInputStream zins=new CZipInputStream(InputStream ins,String encoding);</span>
- <span style="font-size: 14px;">FileOutputStream fos =new FileOutputStream(request.getRealPath("/")+"myzip.zip");
- CZipOutputStream zos=new CZipOutputStream(fos,"GBK");</span><span style="font-size: 14px;">
- </span>
其他地方都不用改,便可以处理中文档名的压缩。
0 0
- zip解压中文乱码解决与使用ant实现zip解压缩
- zip解压中文乱码解决与使用ant实现zip解压缩
- Java实现Zip压缩与解压(解决中文乱码问题)
- Java实现Zip压缩与解压(解决中文乱码问题)
- 解压缩zip文件(解决中文乱码)
- java解压缩zip文件,java创建zip文件,java压缩文件,java解压文件,用到ant.jar解决汉字乱码
- java解压缩zip文件,java创建zip文件,java压缩文件,java解压文件,用到ant.jar解决汉字乱码
- java解压缩zip文件,java创建zip文件,java压缩文件,java解压文件,用到ant.jar解决汉字乱码
- java解压缩zip文件,java创建zip文件,java压缩文件,java解压文件,用到ant.jar解决汉字乱码
- java解压缩zip文件,java创建zip文件,java压缩文件,java解压文件,用到ant.jar解决汉字乱码
- java解压缩zip文件,java创建zip文件,java压缩文件,java解压文件,用到ant.jar解决汉字乱码
- java解压缩zip文件,java创建zip文件,java压缩文件,java解压文件,用到ant.jar解决汉字乱码
- 解压rar和zip(解决中文乱码)
- 使用Ant实现zip/tar的压缩与解压
- linux zip解压缩中文乱码
- linux解压中文zip乱码
- Zip压缩解压缩_已解决中文乱码
- java 压缩解压zip文件--使用ant支持中文
- 自己学习的网页
- 在Java中使用pscp命令上传单个或者多个文件(文件夹)到远程Linux服务器
- android中dip、dp、px、sp和屏幕密度
- js中获取时间new Date()详细介绍
- 网站如何集成支付宝支付接口
- zip解压中文乱码解决与使用ant实现zip解压缩
- 批量修改一个文件夹下所有的文件后缀
- svn进行迁移
- LeetCode – Valid Palindrome (Java)
- Error: no `server' JVM at `C:\Program Files\Java\jre6\bin\server\jvm.dll'
- 物极必反
- 汇编语法
- 关于文件保护路径
- 编程解决Linux下解压zip乱码问题