62,616
社区成员
发帖
与我相关
我的任务
分享
/**
* Begins writing a new ZIP file entry and positions the stream to the start of the entry data. Closes the current
* entry if still active. The default compression method will be used if no compression method was specified for the
* entry, and the current time will be used if the entry has no set modification time.
*
* @param e the ZIP entry to be written
* @exception ZipException if a ZIP format error has occurred
* @exception IOException if an I/O error has occurred
*/
public void putNextEntry(ZipEntry e)
throws IOException
{
ensureOpen();
if (current != null)
{
closeEntry(); // close previous entry
}
if (e.time == -1)
{
e.setTime(System.currentTimeMillis());
}
if (e.method == -1)
{
e.method = method; // use default method
}
switch (e.method)
{
case DEFLATED:
break;
case STORED:
// compressed size, uncompressed size, and crc-32 must all be
// set for entries using STORED compression method
if (e.size == -1)
{
e.size = e.csize;
}
else if (e.csize == -1)
{
e.csize = e.size;
}
else if (e.size != e.csize)
{
throw new ZipException("STORED entry where compressed != uncompressed size");
}
if (e.size == -1 || e.crc == -1)
{
throw new ZipException("STORED entry missing size, compressed size, or crc-32");
}
break;
default:
throw new ZipException("unsupported compression method");
}
if (!names.add(e.name))
{
throw new ZipException("duplicate entry: " + e.name);
}
current = new XEntry(e, written);
xentries.add(current);
writeLOC(current);
}
/**
* Closes the current ZIP entry and positions the stream for writing the next entry.
*
* @exception ZipException if a ZIP format error has occurred
* @exception IOException if an I/O error has occurred
*/
public void closeEntry()
throws IOException
{
ensureOpen();
if (current != null)
{
ZipEntry e = current.entry;
switch (e.method)
{
case DEFLATED:
def.finish();
while (!def.finished())
{
deflate();
}
if ((current.flag & 8) == 0)
{
// verify size, compressed size, and crc-32 settings
if (e.size != def.getBytesRead())
{
throw new ZipException("invalid entry size (expected " + e.size + " but got "
+ def.getBytesRead() + " bytes)");
}
if (e.csize != def.getBytesWritten())
{
throw new ZipException("invalid entry compressed size (expected " + e.csize + " but got "
+ def.getBytesWritten() + " bytes)");
}
if (e.crc != crc.getValue())
{
throw new ZipException("invalid entry CRC-32 (expected 0x" + Long.toHexString(e.crc)
+ " but got 0x" + Long.toHexString(crc.getValue()) + ")");
}
}
else
{
e.size = def.getBytesRead();
e.csize = def.getBytesWritten();
e.crc = crc.getValue();
writeEXT(e);
}
def.reset();
written += e.csize;
break;
case STORED:
// we already know that both e.size and e.csize are the same
if (e.size != written - locoff)
{
throw new ZipException("invalid entry size (expected " + e.size + " but got "
+ (written - locoff) + " bytes)");
}
if (e.crc != crc.getValue())
{
throw new ZipException("invalid entry crc-32 (expected 0x" + Long.toHexString(e.crc)
+ " but got 0x" + Long.toHexString(crc.getValue()) + ")");
}
break;
default:
throw new ZipException("invalid compression method");
}
crc.reset();
current = null;
}
}
/**
* Writes an array of bytes to the current ZIP entry data. This method will block until all the bytes are written.
*
* @param b the data to be written
* @param off the start offset in the data
* @param len the number of bytes that are written
* @exception ZipException if a ZIP file error has occurred
* @exception IOException if an I/O error has occurred
*/
public synchronized void write(byte[] b, int off, int len)
throws IOException
{
ensureOpen();
if (off < 0 || len < 0 || off > b.length - len)
{
throw new IndexOutOfBoundsException();
}
else if (len == 0)
{
return;
}
if (current == null)
{
throw new ZipException("no current ZIP entry");
}
ZipEntry entry = current.entry;
switch (entry.method)
{
case DEFLATED:
super.write(b, off, len);
break;
case STORED:
written += len;
if (written - locoff > entry.size)
{
throw new ZipException("attempt to write past end of STORED entry");
}
out.write(b, off, len);
break;
default:
throw new ZipException("invalid compression method");
}
crc.update(b, off, len);
}
/**
* Finishes writing the contents of the ZIP output stream without closing the underlying stream. Use this method
* when applying multiple filters in succession to the same output stream.
*
* @exception ZipException if a ZIP file error has occurred
* @exception IOException if an I/O exception has occurred
*/
public void finish()
throws IOException
{
ensureOpen();
if (finished)
{
return;
}
if (current != null)
{
closeEntry();
}
if (xentries.size() < 1)
{
throw new ZipException("ZIP file must have at least one entry");
}
// write central directory
long off = written;
for (XEntry xentry : xentries)
writeCEN(xentry);
writeEND(off, written - off);
finished = true;
}
/**
* Closes the ZIP output stream as well as the stream being filtered.
*
* @exception ZipException if a ZIP file error has occurred
* @exception IOException if an I/O error has occurred
*/
public void close()
throws IOException
{
if (!closed)
{
super.close();
closed = true;
}
}
/*
* Writes local file (LOC) header for specified entry.
*/
private void writeLOC(XEntry xentry)
throws IOException
{
ZipEntry e = xentry.entry;
int flag = xentry.flag;
writeInt(LOCSIG); // LOC header signature
writeShort(version(e)); // version needed to extract
writeShort(flag); // general purpose bit flag
writeShort(e.method); // compression method
writeInt(e.time); // last modification time
if ((flag & 8) == 8)
{
// store size, uncompressed size, and crc-32 in data descriptor
// immediately following compressed entry data
writeInt(0);
writeInt(0);
writeInt(0);
}
else
{
writeInt(e.crc); // crc-32
writeInt(e.csize); // compressed size
writeInt(e.size); // uncompressed size
}
byte[] nameBytes = null;
if ("UTF-8".equalsIgnoreCase(fileNameEncoding))
{
nameBytes = getUTF8Bytes(e.name);
}
else
{
nameBytes = e.name.getBytes(fileNameEncoding);
}
writeShort(nameBytes.length);
writeShort(e.extra != null ? e.extra.length : 0);
writeBytes(nameBytes, 0, nameBytes.length);
if (e.extra != null)
{
writeBytes(e.extra, 0, e.extra.length);
}
locoff = written;
}
/*
* Writes extra data descriptor (EXT) for specified entry.
*/
private void writeEXT(ZipEntry e)
throws IOException
{
writeInt(EXTSIG); // EXT header signature
writeInt(e.crc); // crc-32
writeInt(e.csize); // compressed size
writeInt(e.size); // uncompressed size
}
/**
* Sets the ZIP file comment.
*
* @param comment the comment string
* @exception IllegalArgumentException if the length of the specified ZIP file comment is greater than 0xFFFF bytes
*/
public void setComment(String comment)
{
if (comment != null && comment.length() > 0xffff / 3 && getUTF8Length(comment) > 0xffff)
{
throw new IllegalArgumentException("ZIP file comment too long.");
}
this.comment = comment;
}
/**
* Sets the default compression method for subsequent entries. This default will be used whenever the compression
* method is not specified for an individual ZIP file entry, and is initially set to DEFLATED.
*
* @param method the default compression method
* @exception IllegalArgumentException if the specified compression method is invalid
*/
public void setMethod(int method)
{
if (method != DEFLATED && method != STORED)
{
throw new IllegalArgumentException("invalid compression method");
}
this.method = method;
}
/**
* Sets the compression level for subsequent entries which are DEFLATED. The default setting is DEFAULT_COMPRESSION.
*
* @param level the compression level (0-9)
* @exception IllegalArgumentException if the compression level is invalid
*/
public void setLevel(int level)
{
def.setLevel(level);
}
package com.*.*.server.resource.utils;
import java.io.OutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.Vector;
import java.util.HashSet;
import java.util.zip.CRC32;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.ZipException;
/**
*
*此类从JDK中复制出来,添加了对中文文件名的支持
*
* @author zengj
* @version [版本号, 2012-2-9]
* @see [相关类/方法]
* @since [产品/模块版本]
*/
public class CNZipOutPutStream extends DeflaterOutputStream implements ZipConstants
{
private static class XEntry
{
public final ZipEntry entry;
public final long offset;
public final int flag;
public XEntry(ZipEntry entry, long offset)
{
this.entry = entry;
this.offset = offset;
this.flag = (entry.method == DEFLATED && (entry.size == -1 || entry.csize == -1 || entry.crc == -1))
// store size, compressed size, and crc-32 in data descriptor
// immediately following the compressed entry data
? 8
// store size, compressed size, and crc-32 in LOC header
: 0;
}
}
private XEntry current;
private Vector<XEntry> xentries = new Vector<XEntry>();
private HashSet<String> names = new HashSet<String>();
private CRC32 crc = new CRC32();
private long written = 0;
private long locoff = 0;
private String comment;
private int method = DEFLATED;
private boolean finished;
private boolean closed = false;
private String fileNameEncoding = "UTF-8";
private static int version(ZipEntry e)
throws ZipException
{
switch (e.getMethod())
{
case DEFLATED:
return 20;
case STORED:
return 10;
default:
throw new ZipException("unsupported compression method");
}
}
/**
* Checks to make sure that this stream has not been closed.
*/
private void ensureOpen()
throws IOException
{
if (closed)
{
throw new IOException("Stream closed");
}
}
/**
* Compression method for uncompressed (STORED) entries.
*/
public static final int STORED = ZipEntry.STORED;
/**
* Compression method for compressed (DEFLATED) entries.
*/
public static final int DEFLATED = ZipEntry.DEFLATED;
/**
* Creates a new ZIP output stream.
*
* @param out the actual output stream
*/
public CNZipOutPutStream(OutputStream out)
{
super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
try
{
Field f = this.getClass().getDeclaredField("usesDefaultDeflater");
f.setAccessible(true);
f.set(this, true);
}
catch (NoSuchFieldException e)
{ // Ignore
}
catch (IllegalAccessException e)
{// Ignore
}
}
/**
*此方法扩展了JDK的ZIP压缩输出流的默认构造函数,添加了一个内部文件名编码参数
*/
public CNZipOutPutStream(OutputStream out, String fileNameEncoding)
{
this(out);
if (fileNameEncoding != null)
{
this.fileNameEncoding = fileNameEncoding;
}
}