欢迎进入Java社区论坛,与200万技术人员互动交流 >>进入
len = read(tmpbuf, 0, len);
if (len == -1) {
entryEOF = true;
break;
}
total += len;
}
return total;
}
/**
* Closes this input stream and releases any system resources associated
* with the stream.
* @exception IOException if an I/O error has occurred
*/
public void close() throws IOException {
if (!closed) {
super.close();
closed = true;
}
}
private byte[] b = new byte[256];
/*
* Reads local file (LOC) header for next entry.
*/
private ZipEntry readLOC() throws IOException {
try {
readFully(tmpbuf, 0, LOCHDR);
} catch (EOFException e) {
return null;
}
if (get32(tmpbuf, 0) != LOCSIG) {
return null;
}
// get the entry name and create the ZipEntry first
int len = get16(tmpbuf, LOCNAM);
int blen = b.length;
if (len > blen) {
do
blen = blen * 2;
while (len > blen);
b = new byte[blen];
}
readFully(b, 0, len);
ZipEntry e = createZipEntry(getUTF8String(b, 0, len));
// now get the remaining fields for the entry
flag = get16(tmpbuf, LOCFLG);
if ((flag & 1) == 1) {
throw new ZipException(“encrypted ZIP entry not supported”);
}
e.method = get16(tmpbuf, LOCHOW);
e.time = get32(tmpbuf, LOCTIM);
if ((flag & 8) == 8) {
/* “Data Descriptor” present */
if (e.method != DEFLATED) {
throw new ZipException(
”only DEFLATED entries can have EXT descriptor”);
}
} else {
e.crc = get32(tmpbuf, LOCCRC);
e.csize = get32(tmpbuf, LOCSIZ);
e.size = get32(tmpbuf, LOCLEN);
}
len = get16(tmpbuf, LOCEXT);
if (len > 0) {
byte[] bb = new byte[len];
readFully(bb, 0, len);
e.setExtra(bb);
}
return e;
}
/*
* Fetches a UTF8-encoded String from the specified byte array.
*/
private static String getUTF8String(byte[] b, int off, int len)
{
try
{
String s = new String(b, off, len, “GBK”);
return s;
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
//以上为新添加的解决GBK乱码的
// First, count the number of characters in the sequence
int count = 0;
int max = off + len;
int i = off;
while (i < max)
{
int c = b[i++] & 0xff;
switch (c >> 4)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
// 0xxxxxxx
count++;
break;
case 12:
case 13:
// 110xxxxx 10xxxxxx
if ((int) (b[i++] & 0xc0) != 0x80)
{
throw new IllegalArgumentException();
}
count++;
break;
case 14:
// 1110xxxx 10xxxxxx 10xxxxxx
if (((int) (b[i++] & 0xc0) != 0x80)
|| ((int) (b[i++] & 0xc0) != 0x80))
{
throw new IllegalArgumentException();
}
count++;
break;
default:
// 10xxxxxx, 1111xxxx
throw new IllegalArgumentException();
}
}
if (i != max)
{
throw new IllegalArgumentException();
}
// Now decode the characters…
char[] cs = new char[count];
i = 0;
while (off < max)
{
int c = b[off++] & 0xff;
switch (c >> 4)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
// 0xxxxxxx
cs[i++] = (char) c;
break;
case 12:
case 13:
// 110xxxxx 10xxxxxx
cs[i++] = (char) (((c & 0x1f) << 6) | (b[off++] & 0x3f));
break;
case 14:
// 1110xxxx 10xxxxxx 10xxxxxx
int t = (b[off++] & 0x3f) << 6;
cs[i++] = (char) (((c & 0x0f) << 12) | t | (b[off++] & 0x3f));
break;
default:
// 10xxxxxx, 1111xxxx
throw new IllegalArgumentException();
}
}
return new String(cs, 0, count);
}
/**
* Creates a new ZipEntry object for the specified
* entry name.
*
* @param name the ZIP file entry name
* @return the ZipEntry just created
*/
protected ZipEntry createZipEntry(String name) {
return new ZipEntry(name);
}
/*
* Reads end of deflated entry as well as EXT descriptor if present.
*/
private void readEnd(ZipEntry e) throws IOException {
int n = inf.getRemaining();
if (n > 0) {
((PushbackInputStream)in).unread(buf, len – n, n);
}
if ((flag & 8) == 8) {
/* “Data Descriptor” present */
readFully(tmpbuf, 0, EXTHDR);
long sig = get32(tmpbuf, 0);
if (sig != EXTSIG) { // no EXTSIG present
e.crc = sig;
e.csize = get32(tmpbuf, EXTSIZ – EXTCRC);
e.size = get32(tmpbuf, EXTLEN – EXTCRC);
((PushbackInputStream)in).unread(
tmpbuf, EXTHDR – EXTCRC – 1, EXTCRC);
} else {
e.crc = get32(tmpbuf, EXTCRC);
e.csize = get32(tmpbuf, EXTSIZ);
e.size = get32(tmpbuf, EXTLEN);
}
}
if (e.size != inf.getBytesWritten()) {
throw new ZipException(
”invalid entry size (expected ” + e.size +
” but got ” + inf.getBytesWritten() + ” bytes)”);
}
if (e.csize != inf.getBytesRead()) {
throw new ZipException(
”invalid entry compressed size (expected ” + e.csize +
” but got ” + inf.getBytesRead() + ” bytes)”);
}
if (e.crc != crc.getValue()) {
throw new ZipException(
”invalid entry CRC (expected 0x” + Long.toHexString(e.crc) +
” but got 0x” + Long.toHexString(crc.getValue()) + “)”);
}
}
/*
* Reads bytes, blocking until all bytes are read.
*/
private void readFully(byte[] b, int off, int len) throws IOException {
while (len > 0) {
int n = in.read(b, off, len);
if (n == -1) {
throw new EOFException();
}
off += n;
len -= n;
}
}
/*
* Fetches unsigned 16-bit value from byte array at specified offset.
* The bytes are assumed to be in Intel (little-endian) byte order.
*/
private static final int get16(byte b[], int off) {
return (b[off] & 0xff) | ((b[off+1] & 0xff) << 8);
}
/*
* Fetches unsigned 32-bit value from byte array at specified offset.
* The bytes are assumed to be in Intel (little-endian) byte order.
*/
private static final long get32(byte b[], int off) {
return get16(b, off) | ((long)get16(b, off+2) << 16);
}
}
7. 在包中新建ZipOutputStream类,代码如下:
ZipOutputStream.java:
package cn.edu.xdian.crytoll;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Vector;
import java.util.zip.CRC32;
import java.util.zip.Deflater;
import java.util.zip.ZipException;
/**
* This class implements an output stream filter for writing files in the
* ZIP file format. Includes support for both compressed and uncompressed
* entries.
*
* @author David Connelly
* @version 1.35, 07/31/06
*/
public
class ZipOutputStream 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 xentries = new Vector();
private HashSet names = new HashSet();
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 static int version(ZipEntry e) throws ZipException {
switch (e.method) {
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 ZipOutputStream(OutputStream out) {
super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
usesDefaultDeflater = true;
}
/**
* 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);
}
/**
* 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()) + “)”);
}
[1][2][3][4]
明天是世上增值最快的一块土地,因它充满了希望