📄 zipfile.java
字号:
{ byte[] extra = new byte[extraLen]; raf.readFully(extra); entry.setExtra(extra); } if (commentLen > 0) { raf.readFully(buffer, 0, commentLen); try { entry.setComment(new String(buffer, 0, commentLen, "UTF-8")); } catch (UnsupportedEncodingException uee) { throw new AssertionError(uee); } } entry.offset = offset; entries.put(name, entry); } } /** * Closes the ZipFile. This also closes all input streams given by * this class. After this is called, no further method should be * called. * * @exception IOException if a i/o error occured. */ public void close() throws IOException { RandomAccessFile raf = this.raf; if (raf == null) return; synchronized (raf) { closed = true; entries = null; raf.close(); } } /** * Calls the <code>close()</code> method when this ZipFile has not yet * been explicitly closed. */ protected void finalize() throws IOException { if (!closed && raf != null) close(); } /** * Returns an enumeration of all Zip entries in this Zip file. * * @exception IllegalStateException when the ZipFile has already been closed */ public Enumeration entries() { checkClosed(); try { return new ZipEntryEnumeration(getEntries().values().iterator()); } catch (IOException ioe) { return EmptyEnumeration.getInstance(); } } /** * Checks that the ZipFile is still open and reads entries when necessary. * * @exception IllegalStateException when the ZipFile has already been closed. * @exception IOException when the entries could not be read. */ private HashMap getEntries() throws IOException { synchronized(raf) { checkClosed(); if (entries == null) readEntries(); return entries; } } /** * Searches for a zip entry in this archive with the given name. * * @param name the name. May contain directory components separated by * slashes ('/'). * @return the zip entry, or null if no entry with that name exists. * * @exception IllegalStateException when the ZipFile has already been closed */ public ZipEntry getEntry(String name) { checkClosed(); try { HashMap entries = getEntries(); ZipEntry entry = (ZipEntry) entries.get(name); // If we didn't find it, maybe it's a directory. if (entry == null && !name.endsWith("/")) entry = (ZipEntry) entries.get(name + '/'); return entry != null ? new ZipEntry(entry, name) : null; } catch (IOException ioe) { return null; } } //access should be protected by synchronized(raf) private byte[] locBuf = new byte[LOCHDR]; /** * Checks, if the local header of the entry at index i matches the * central directory, and returns the offset to the data. * * @param entry to check. * @return the start offset of the (compressed) data. * * @exception IOException if a i/o error occured. * @exception ZipException if the local header doesn't match the * central directory header */ private long checkLocalHeader(ZipEntry entry) throws IOException { synchronized (raf) { raf.seek(entry.offset); raf.readFully(locBuf); if (readLeInt(locBuf, 0) != LOCSIG) throw new ZipException("Wrong Local header signature: " + name); if (entry.getMethod() != readLeShort(locBuf, LOCHOW)) throw new ZipException("Compression method mismatch: " + name); if (entry.getName().length() != readLeShort(locBuf, LOCNAM)) throw new ZipException("file name length mismatch: " + name); int extraLen = entry.getName().length() + readLeShort(locBuf, LOCEXT); return entry.offset + LOCHDR + extraLen; } } /** * Creates an input stream reading the given zip entry as * uncompressed data. Normally zip entry should be an entry * returned by getEntry() or entries(). * * This implementation returns null if the requested entry does not * exist. This decision is not obviously correct, however, it does * appear to mirror Sun's implementation, and it is consistant with * their javadoc. On the other hand, the old JCL book, 2nd Edition, * claims that this should return a "non-null ZIP entry". We have * chosen for now ignore the old book, as modern versions of Ant (an * important application) depend on this behaviour. See discussion * in this thread: * http://gcc.gnu.org/ml/java-patches/2004-q2/msg00602.html * * @param entry the entry to create an InputStream for. * @return the input stream, or null if the requested entry does not exist. * * @exception IllegalStateException when the ZipFile has already been closed * @exception IOException if a i/o error occured. * @exception ZipException if the Zip archive is malformed. */ public InputStream getInputStream(ZipEntry entry) throws IOException { checkClosed(); HashMap entries = getEntries(); String name = entry.getName(); ZipEntry zipEntry = (ZipEntry) entries.get(name); if (zipEntry == null) return null; long start = checkLocalHeader(zipEntry); int method = zipEntry.getMethod(); InputStream is = new BufferedInputStream(new PartialInputStream (raf, start, zipEntry.getCompressedSize())); switch (method) { case ZipOutputStream.STORED: return is; case ZipOutputStream.DEFLATED: return new InflaterInputStream(is, new Inflater(true)); default: throw new ZipException("Unknown compression method " + method); } } /** * Returns the (path) name of this zip file. */ public String getName() { return name; } /** * Returns the number of entries in this zip file. * * @exception IllegalStateException when the ZipFile has already been closed */ public int size() { checkClosed(); try { return getEntries().size(); } catch (IOException ioe) { return 0; } } private static class ZipEntryEnumeration implements Enumeration { private final Iterator elements; public ZipEntryEnumeration(Iterator elements) { this.elements = elements; } public boolean hasMoreElements() { return elements.hasNext(); } public Object nextElement() { /* We return a clone, just to be safe that the user doesn't * change the entry. */ return ((ZipEntry)elements.next()).clone(); } } private static class PartialInputStream extends InputStream { private final RandomAccessFile raf; long filepos, end; public PartialInputStream(RandomAccessFile raf, long start, long len) { this.raf = raf; filepos = start; end = start + len; } public int available() { long amount = end - filepos; if (amount > Integer.MAX_VALUE) return Integer.MAX_VALUE; return (int) amount; } public int read() throws IOException { if (filepos == end) return -1; synchronized (raf) { raf.seek(filepos++); return raf.read(); } } public int read(byte[] b, int off, int len) throws IOException { if (len > end - filepos) { len = (int) (end - filepos); if (len == 0) return -1; } synchronized (raf) { raf.seek(filepos); int count = raf.read(b, off, len); if (count > 0) filepos += len; return count; } } public long skip(long amount) { if (amount < 0) throw new IllegalArgumentException(); if (amount > end - filepos) amount = end - filepos; filepos += amount; return amount; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -