ZipFilepublic class ZipFile extends Object implements ZipConstantsThis class provides random read access to a ZIP-archive file.
While {@code ZipInputStream} provides stream based read access to a
ZIP-archive, this class implements more efficient (file based) access
and makes use of the central directory within a ZIP-archive.
Use {@code ZipOutputStream} if you want to create an archive.
A temporary ZIP file can be marked for automatic deletion upon closing it.
|
Fields Summary |
---|
String | fileName | File | fileToDeleteOnClose | public static final int | OPEN_READOpen zip file for read. | public static final int | OPEN_DELETEDelete zip file when closed. | private RandomAccessFile | mRaf | ZipEntry.LittleEndianReader | ler | private ArrayList | mEntryList | private HashMap | mFastLookup |
Constructors Summary |
---|
public ZipFile(File file)Constructs a new {@code ZipFile} with the specified file.
this(file, OPEN_READ);
| public ZipFile(File file, int mode)Opens a file as ZIP-archive. "mode" must be {@code OPEN_READ} or
{@code OPEN_DELETE} . The latter sets the "delete on exit" flag through a
file.
if (mode == (OPEN_READ | OPEN_DELETE))
fileToDeleteOnClose = file; // file.deleteOnExit();
else if (mode != OPEN_READ)
throw new IllegalArgumentException("invalid mode");
fileName = file.getPath();
mRaf = new RandomAccessFile(fileName, "r");
mEntryList = new ArrayList<ZipEntry>();
readCentralDir();
/*
* No LinkedHashMap yet, so optimize lookup-by-name by creating
* a parallel data structure.
*/
mFastLookup = new HashMap<String, ZipEntry>(mEntryList.size() * 2);
for (int i = 0; i < mEntryList.size(); i++) {
ZipEntry entry = mEntryList.get(i);
mFastLookup.put(entry.getName(), entry);
}
| public ZipFile(String name)Opens a ZIP archived file.
this(new File(name), OPEN_READ);
|
Methods Summary |
---|
public void | close()Closes this ZIP file.
RandomAccessFile raf = mRaf;
if (raf != null) { // Only close initialized instances
synchronized(raf) {
mRaf = null;
raf.close();
}
if (fileToDeleteOnClose != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
new File(fileName).delete();
return null;
}
});
// fileToDeleteOnClose.delete();
fileToDeleteOnClose = null;
}
}
| public java.util.Enumeration | entries()Returns an enumeration of the entries. The entries are listed in the
order in which they appear in the ZIP archive.
return new Enumeration<ZipEntry>() {
private int i = 0;
public boolean hasMoreElements() {
if (mRaf == null) throw new IllegalStateException("Zip File closed.");
return i < mEntryList.size();
}
public ZipEntry nextElement() {
if (mRaf == null) throw new IllegalStateException("Zip File closed.");
if (i >= mEntryList.size())
throw new NoSuchElementException();
return (ZipEntry) mEntryList.get(i++);
}
};
| protected void | finalize()
close();
| public java.util.zip.ZipEntry | getEntry(java.lang.String entryName)Gets the ZIP entry with the specified name from this {@code ZipFile}.
if (entryName != null) {
ZipEntry ze = mFastLookup.get(entryName);
if (ze == null) ze = mFastLookup.get(entryName + "/");
return ze;
}
throw new NullPointerException();
| public java.io.InputStream | getInputStream(java.util.zip.ZipEntry entry)Returns an input stream on the data of the specified {@code ZipEntry}.
/*
* Make sure this ZipEntry is in this Zip file. We run it through
* the name lookup.
*/
entry = getEntry(entry.getName());
if (entry == null)
return null;
/*
* Create a ZipInputStream at the right part of the file.
*/
RandomAccessFile raf = mRaf;
if (raf != null) {
synchronized (raf) {
// Unfortunately we don't know the entry data's start position.
// All we have is the position of the entry's local header.
// At position 28 we find the length of the extra data.
// In some cases this length differs from the one coming in
// the central header!!!
RAFStream rafstrm = new RAFStream(raf, entry.mLocalHeaderRelOffset + 28);
int localExtraLenOrWhatever = ler.readShortLE(rafstrm);
// Now we need to skip the name
// and this "extra" data or whatever it is:
rafstrm.skip(entry.nameLen + localExtraLenOrWhatever);
rafstrm.mLength = rafstrm.mOffset + entry.compressedSize;
if (entry.compressionMethod == ZipEntry.DEFLATED) {
return new InflaterInputStream(rafstrm, new Inflater(true));
} else {
return rafstrm;
}
}
}
throw new IllegalStateException("Zip File closed");
| public java.lang.String | getName()Gets the file name of this {@code ZipFile}.
return fileName;
| private void | readCentralDir()
long scanOffset, stopOffset;
long sig;
/*
* Scan back, looking for the End Of Central Directory field. If
* the archive doesn't have a comment, we'll hit it on the first
* try.
*
* No need to synchronize mRaf here -- we only do this when we
* first open the Zip file.
*/
scanOffset = mRaf.length() - ENDHDR;
if (scanOffset < 0)
throw new ZipException("too short to be Zip");
stopOffset = scanOffset - 65536;
if (stopOffset < 0)
stopOffset = 0;
while (true) {
mRaf.seek(scanOffset);
if (ZipEntry.readIntLE(mRaf) == 101010256L)
break;
//System.out.println("not found at " + scanOffset);
scanOffset--;
if (scanOffset < stopOffset)
throw new ZipException("EOCD not found; not a Zip archive?");
}
/*
* Found it, read the EOCD.
*
* For performance we want to use buffered I/O when reading the
* file. We wrap a buffered stream around the random-access file
* object. If we just read from the RandomAccessFile we'll be
* doing a read() system call every time.
*/
RAFStream rafs = new RAFStream(mRaf, mRaf.getFilePointer());
BufferedInputStream bin = new BufferedInputStream(rafs, ENDHDR);
int diskNumber, diskWithCentralDir, numEntries, totalNumEntries;
//long centralDirSize;
long centralDirOffset;
//int commentLen;
diskNumber = ler.readShortLE(bin);
diskWithCentralDir = ler.readShortLE(bin);
numEntries = ler.readShortLE(bin);
totalNumEntries = ler.readShortLE(bin);
/*centralDirSize =*/ ler.readIntLE(bin);
centralDirOffset = ler.readIntLE(bin);
/*commentLen =*/ ler.readShortLE(bin);
if (numEntries != totalNumEntries ||
diskNumber != 0 ||
diskWithCentralDir != 0)
throw new ZipException("spanned archives not supported");
/*
* Seek to the first CDE and read all entries.
*/
rafs = new RAFStream(mRaf, centralDirOffset);
bin = new BufferedInputStream(rafs, 4096);
for (int i = 0; i < numEntries; i++) {
ZipEntry newEntry;
newEntry = new ZipEntry(ler, bin);
mEntryList.add(newEntry);
}
| public int | size()Returns the number of {@code ZipEntries} in this {@code ZipFile}.
return mEntryList.size();
|
|