Java中压缩与解压--中文文件名乱码解决办法

时间:2023-02-10 12:17:35

http://xxw8393.blog.163.com/blog/static/37256834200993051226320/

 

java对於文字的编码是以 unicode为基础,因此,若是以ZipInputStream及ZipOutputStream来处理压缩及解压缩的工作,碰到中文档名或路径,那当然是以unicode来处理罗!但是,现在市面上的压缩及解压缩软体,例如winzip,却是不支援unicode的,一碰到档名以unicode编码的档案,它就不处理。那要如何才能做出让WinRar能够处理的压缩档呢?那就得从修改ZipInputStream及ZipOutputStream对於档名的编码方式来着手了。我们可以从jdk的src.zip取得ZipInputStream及ZipOutputStream的原始码来加以修改

一、ZipOutputStream.java
1.从jdk的src.zip取得ZipOutputStream.java原始码,另存到一个新文件中,档名改为CnZipOutputStream.java。
2.开始修改原始码,将class名称改为CnZipOutputStream
3.建构式也必须更改为CnZipOutputStream
4.新增member,这个member记录编码方式
  private String encoding="UTF-8";
5.再新增一个建构式(这个建构式可以让这个class在new的时候,设定档名的编码)
  public CZipOutputStream(OutputStream out,String encoding) {
     this(out);
     this.encoding=encoding;
  }
6.找到byte[] nameBytes = getUTF8Bytes(e.name);(有二个地方),将它修改如下:

  1. byte[] nameBytes = null;
  2.  try
  3.  {
  4.  if (this.encoding.toUpperCase().equals("UTF-8"))
  5.  nameBytes =getUTF8Bytes(e.name);
  6.  else
  7.  nameBytes= e.name.getBytes(this.encoding);
  8.  }
  9.  catch(Exception byteE)
  10.  {
  11.  nameBytes=getUTF8Bytes(e.name);
  12.  }



二、ZipInputStream.java
1.从jdk的src.zip取得ZipInputStream.java原始码,另存到一个新文件中,档名改为CnZipInputStream.java。
2.开始修改原始码,将class名称改为CnZipInputStream
3.建构式也必须更改为CnZipInputStream
4.新增member,这个member记录编码方式
  private String encoding="UTF-8";
5.再新增一个建构式如下(这个建构式可以让这个class在new的时候,设定档名的编码)
public CZipInputStream(InputStream in,String encoding) {
  this(in);
  this.encoding=encoding;
}

6.找到ZipEntry e = createZipEntry(getUTF8String(b, 0, len));这一行,将它改成如下:

  1. ZipEntry e=null;
  2.  try
  3.  {
  4.  if (this.encoding.toUpperCase().equals("UTF-8"))
  5.  e=createZipEntry(getUTF8String(b, 0, len));
  6.  else
  7.  e=createZipEntry(new String(b,0,len,this.encoding));
  8.  }
  9.  catch(Exception byteE)
  10.  {
  11.  e=createZipEntry(getUTF8String(b, 0, len));
  12.  }




以上两个档案储存後compile产生CZipOutputStream.class及CZipInputStream.class,使用winzip开启 [java_home]/jre/lib/rt.jar这个档案,将CnZipOutputStream.class及 CnZipInputStream.class加进去,以後当压缩及解压缩时有中文档名及路径的问题时,就可以指定编码方式来处理了。

使用方法:
CnZipOutputStream zos=new CnZipOutputStream(OutputStream os,String encoding);
CnZipInputStream zins=new CnZipInputStream(InputStream ins,String encoding);

对于前面文章中文件打包下载中遇到的中文文件问题,解决手法是:
OutputStream os = response.getOutputStream();
CnZipOutputStream zos = new CnZipOutputStream(os,"gbk"); //加上中文编码类型


或者不用sun的解压包 而换用apache的解压包

第二种方法是用ant.jar带的org.apache.tools.zip,而且看了很多类似的文章说能够解决乱码问题了,也许是自己没弄明白吧,把代码拷来测试的时候是能够正常的解压缩了,可乱码问题还是有的,我开发环境编码是UTF-8的,一样的代码不知道他们乱码问题是怎么处理的,我还得多学习学习,

花了很长的时间研究代码,后来改动了下结果乱码问题就解决了,可能是和我的编码格式有关吧,把我整理的代码放这方便以后可以在看看(都是在网上找的资料,呵呵 不是本人写的)

package com.bjtxx.lms.server.tools;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.tools.zip.ZipOutputStream;

public class ZipTest {
 
  public static void zip(ZipOutputStream out, File f, String base, boolean first)
      throws Exception {
    if (first) {
      if (f.isDirectory()) {
        out.putNextEntry(new org.apache.tools.zip.ZipEntry("/"));
        base = base + f.getName();
        first = false;
      } else
        base = f.getName();
    }
    if (f.isDirectory()) {
      File[] fl = f.listFiles();
      base = base + "/";
      for (int i = 0; i < fl.length; i++) {
        zip(out, fl[i], base + fl[i].getName(), first);
      }
    } else {
      out.putNextEntry(new org.apache.tools.zip.ZipEntry(base));
      FileInputStream in = new FileInputStream(f);
      int b;
      System.out.println(base);
      while ((b = in.read()) != -1) {
        out.write(b);
      }
      in.close();
    }
  }

 
  @SuppressWarnings("unchecked")
  public static void unZipFileByOpache(org.apache.tools.zip.ZipFile zipFile,
      String unZipRoot) throws Exception, IOException {
    java.util.Enumeration e = zipFile.getEntries();
    System.out.println(zipFile.getEncoding());
    org.apache.tools.zip.ZipEntry zipEntry;
    while (e.hasMoreElements()) {
      zipEntry = (org.apache.tools.zip.ZipEntry) e.nextElement();
      InputStream fis = zipFile.getInputStream(zipEntry);
      if (zipEntry.isDirectory()) {
      } else {
        File file = new File(unZipRoot + File.separator + zipEntry.getName());
        File parentFile = file.getParentFile();
        parentFile.mkdirs();
        FileOutputStream fos = new FileOutputStream(file);
        byte[] b = new byte[1024];
        int len;
        while ((len = fis.read(b, 0, b.length)) != -1) {
          fos.write(b, 0, len);
        }
        fos.close();
        fis.close();
      }
    }
  }

  public static void ZipFile(String zipFileName, String inputFileName)
      throws Exception {
    org.apache.tools.zip.ZipOutputStream out = new org.apache.tools.zip.ZipOutputStream(
        new FileOutputStream(zipFileName));
    out.setEncoding("gbk");//设置的和文件名字格式一样或开发环境编码设置一样的话就能正常显示了
    File inputFile = new File(inputFileName);
    zip(out, inputFile, "", true);
    System.out.println("zip done");
    out.close();
  }

  public static void unZipFile(String unZipFileName, String unZipPath)
      throws Exception {
    org.apache.tools.zip.ZipFile zipFile = new org.apache.tools.zip.ZipFile(
        unZipFileName, "gbk");
    unZipFileByOpache(zipFile, unZipPath);
    System.out.println("unZip Ok");
  }

 

public static void main(String[] args) throws Exception {
    ZipFile("e:zf.zip", "e:zf.xml");
    // unZipFile("e:zf.zip", "e:");
  }
}