Reason:Java encoding of the text is based on Unicode, so if Zipinputstream and Zipoutputstream to deal with the compression and decompression work, encountered in the Chinese file name or path, it is of course the Unicode to deal with ROM. However, now on the market compression and decompression software, such as WinZip, but does not support Unicode, a file name in Unicode-encoded file, it will not be processed.
So how do you make the compression file that WinZip can handle? There are two ways of doing this:
one is to use Apache ant to implement zip decompression, the other is to modify the JDK's own zip tool class source code
because the ant internal is multi-threaded read files, the extracted files are chaotic, but the efficiency is significantly higher than the JDK zip way. It is recommended to use the Ant zip implementation.
the first use of the ant implementation of the zip decompression, which extracted garbled note to usepublic void UnZip (String unzipfilename,string OutputPath) where
this.zipfile = new ZipFile (unzipfilename, "GB18030");Is the key to solve the Chinese name garbled.
Import java.io.*;
Import org.apache.tools.zip.*;
Import java.util.Enumeration; /** *<p> * <b> function: Zip compression, decompression (support Chinese file name) </b> *<p> * Description: Using the Apache ant provided zip tool org.apache.tools.zip implementation Zi
P compression and decompression function.
* Solved the problem that the Java.util.zip package does not support Chinese characters.
* * @author Winty * @modifier Vernon.zheng */public class Antzip {private ZipFile zipfile; Private Zipoutputstream zipout;
Compressed zip private zipentry zipentry; private static int bufSize;
Size of bytes private byte[] buf;
private int readedbytes; Used in compression.
The absolute parent path to be removed in order to change the absolute path to a relative path.
Private String deleteabsoluteparent; /** * Construction method.
The default buffer size is 512 bytes.
*/Public Antzip () {this (512);
}/** * Constructor method.
* * @param bufSize * Specifies the buffer size when compressing or decompressing */public antzip (int bufSize) {this.bufsize = bufSize;
This.buf = new Byte[this.bufsize];
Deleteabsoluteparent = null;
/** * Compress all files and directories within the folder. * * @param zipdirectory * Folder name required for compression */public void Dozip (String zipdirectory) {File Zipdir = new Fil E(zipdirectory);
Dozip (new file[] {zipdir}, Zipdir.getname ()); }/** * Compress multiple files or directories. You can specify multiple individual files or directories.
<code>dozip (String zipdirectory) </code> * Compresses the entire folder directly.
* * @param files * The <code>File</code> array to compress the file or directory.
* @param zipfilename * ZIP file name after compression, if the suffix is not ". zip", the suffix ". zip" is added automatically. */public void Dozip (file[] files, String zipfilename) {//No compressed file name specified, default to ' ZipFile ' if (zipfilename = null | | zipfilen
Ame.equals ("")) Zipfilename = "ZipFile";
Add the ". zip" suffix 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 (); }}/** * Compress files and directories. Called by Dozip () * * @param files * file to compress * @param zipout * Zip output stream * @param isabsolute * is the root path of the absolute path to be removed. Because CompressfilES () * will be called recursively, so it is not possible to use deleteabsoluteparent. You must use Isabsolute to indicate that * compressfiles () is the first call, not a subsequent recursive call. That is, if the path to be compressed is * E:\temp, then the first call, Isabsolute=true, then deleteabsoluteparent will record * The path to be deleted is e:\, when compressed subdirectory e:\t When Emp\folder, Isabsolute=false, * and then recursively calls Compressfiles (), Deleteabsoluteparent is still e:\. This ensures that the * E:\temp and its subdirectories are correctly converted to relative directories. This way, compression is not an error.
Otherwise, the absolute path e:\ will also be written to the compressed file. */private void Compressfiles (file[] files, Zipoutputstream zipout, Boolean isabsolute) throws IOException {for (F Ile file:files) {if (file = = null) continue;//Empty file object//Delete Absolute parent path if (File.isabsolute ()) {if (ISABSO
lute) {deleteabsoluteparent = File.getparentfile (). GetAbsolutePath ();
Deleteabsoluteparent = Appendseparator (deleteabsoluteparent);
}} else Deleteabsoluteparent = "";
if (File.isdirectory ()) {//Is the directory Compressfolder (file, zipout);
} else {//Is file Compressfile (files, zipout);
}
}
}
/** * Compress files or empty directories.
Called by Compressfiles (). * * @param file * requires compressed files * @param zipout * Zip output stream */public void Compressfile (file file,
Zipoutputstream zipout) throws IOException {String fileName = file.tostring (); /* Remove the absolute parent path.
*/if (File.isabsolute ()) FileName = Filename.substring (Deleteabsoluteparent.length ());
if (filename = = NULL | | fileName = = "") return; /* * Because it is an empty directory, add a "/" at the end. Otherwise it will be treated as an empty file.
In the ZipEntry isdirectory () method, the directory ends with "/".
* Org.apache.tools.zip.ZipEntry:public Boolean isdirectory () {return * GetName (). EndsWith ("/");}
*/if (file.isdirectory ()) filename = filename + "/";//cannot be used here "\ \" Zipout.putnextentry (new ZipEntry (FileName));
If it is a file, read it, and if it is an empty directory, go to Zipout.closeentry () without reading it.
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 (); }/** * Recursive completion of directory file reads.
Called by Compressfiles (). * * @param dir * File object to be processed * @param zipout * Zip output stream */private void Compressfolder (file D
IR, Zipoutputstream zipout) throws IOException {file[] files = dir.listfiles ();
if (Files.length = = 0)//If the directory is empty, empty directories are compressed separately.
Compressfile (dir, zipout);
else//If the directory is not empty, the directories and files are processed separately.
Compressfiles (Files, zipout, false);
}/** * Unzip the specified zip file. * * @param unzipfilename * ZIP file name needed to unzip */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 ()) {//is the directory, then create the File.mkdirs ();
} else {//is file//if the parent directory of the specified file does not exist, it is created.
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 (); }}/** * Unzip the specified zip file.
where "GB18030" to solve the Chinese garbled * * @param unzipfilename * Need to unzip the zip file name * @param outputPath * Output Path * *
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 ()) {//is the directory, the creation of File.mkdirs ();
} else {//is file//if the parent directory of the specified file does not exist, it is created.
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 (); }}/** * Add File.separator * to file path or end of directory * * @param fileName * need to add path delimiter path * @return If the path already has a separator, it is returned as is,
Otherwise, it is returned after the separator is added.
*/private string Appendseparator (string path) {if (!path.endswith (file.separator)) path + = File.separator;
return path;
}/** * Unzip the specified zip file. * * @param unzipfile * Need to unzip the zip file object */public void UnZip (File unzipfile) {UnZip (unzipfile.tostring ());
}/** * Sets the buffer size when compressing or decompressing.
* * @param bufSize * Buffer size */public void setbufsize (int bufSize) {this.bufsize = bufSize; }//Main function for testing Antzip class/* public static void Main (string[] args) throws exception{* if (args.length>=2) {Antzip Zi
p = new Antzip (); * * IF (args[0].equals ("-zip")) {//Convert all subsequent parameters to File object file[] files = new file[* args.length-1]; for (int i = 0;i < Args.length-1;
i++) {files = new * File (args[i + 1]);}
* *//The first file name as ZIP file name 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 ("compression: Java Antzip-zip [DirectoryName | FileName] ...
"); * SYSTEM.OUT.PRINTLN ("extract: Java antzip-unzip filename.zip"); }
*/
}
The second one starts with modifying Zipinputstream and Zipoutputstream to encode the file name.
we can obtain the original code of Zipinputstream and Zipoutputstream from the src.zip of the JDK to modify it:
First, Zipoutputstream.java
1. Obtain the Zipoutputstream.java source code from the JDK's src.zip, save the new file to the C:/java/util/zip folder, and change the file name to Czipoutputstream.java.
2. Start modifying the original code and changing the class name to Czipoutputstream
3. The constructor must also be changed to Czipoutputstream
4. Add Member, this member record encoding method
Private String encoding= "UTF-8";
5. Add a new constructor (this constructor allows the class to encode the file name at new time)
Public Czipoutputstream (OutputStream out,string encoding) {
super (out, new Deflater (deflater.default_compression , true));
Usesdefaultdeflater = true;
this.encoding=encoding;
6. Find byte[] namebytes = getutf8bytes (e.name);(there are two places), modify it as follows:
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);
7. Save the file in C:/java/util/zip this folder, please remember that the path structure must be
To put Czipoutputstream.class in the right package structure.
Second, Zipinputstream.java
1. Obtain the Zipinputstream.java source code from the JDK's src.zip, save the new file to the C:/java/util/zip folder, and change the file name to Czipinputstream.java.
2. Start modifying the original code and changing the class name to Czipinputstream
3. The constructor must also be changed to Czipinputstream
4. Add Member, this member record encoding method
Private String encoding= "UTF-8";
5. Add a new constructor as follows (this constructor allows the class to encode the file name when it is new)
Public Czipinputstream (InputStream in,string encoding) {
super (new Pushbackinputstream (in,512), New Inflater (True );
Usesdefaultinflater = true;
if (in = = null) {
throw new NullPointerException ("is null");
}
this.encoding=encoding;
6. Find ZipEntry e = Createzipentry (getutf8string (b, 0, Len)); This line, change it to the following:
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));
7. Save the file in C:/java/util/zip this folder, please remember that the path structure must be, in order to put Czipinputstream.class in the correct package structure
After storing the above two files compile generate Czipoutputstream.class and Czipinputstream.class, using WinZip to open [java_home]/jre/lib/ Rt.jar this file, will Czipoutputstream.class and czipinputstream.class add in, remember "save full path info" must tick.
After the compression and decompression of the Chinese file name and the path of the problem, you can specify the encoding method to handle.
Czipoutputstream zos=new Czipoutputstream (outputstream os,string encoding);
Czipinputstream zins=new Czipinputstream (inputstream ins,string encoding);
Take "Compression and decompression (1)" As an example:
FileOutputStream Fos =new FileOutputStream (Request.getrealpath ("/") + "Myzip.zip");
Czipoutputstream zos=new czipoutputstream (FOS, "GBK");
Other places do not have to change, you can process the compression of the document name.