⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 zipoutputstream.java

📁 Use the links below to download a source distribution of Ant from one of our mirrors. It is good pra
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/* *  Licensed to the Apache Software Foundation (ASF) under one or more *  contributor license agreements.  See the NOTICE file distributed with *  this work for additional information regarding copyright ownership. *  The ASF licenses this file to You under the Apache License, Version 2.0 *  (the "License"); you may not use this file except in compliance with *  the License.  You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * *  Unless required by applicable law or agreed to in writing, software *  distributed under the License is distributed on an "AS IS" BASIS, *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *  See the License for the specific language governing permissions and *  limitations under the License. * */package org.apache.tools.zip;import java.io.File;import java.io.FileOutputStream;import java.io.FilterOutputStream;import java.io.IOException;import java.io.OutputStream;import java.io.RandomAccessFile;import java.io.UnsupportedEncodingException;import java.util.Date;import java.util.Hashtable;import java.util.Vector;import java.util.zip.CRC32;import java.util.zip.Deflater;import java.util.zip.ZipException;/** * Reimplementation of {@link java.util.zip.ZipOutputStream * java.util.zip.ZipOutputStream} that does handle the extended * functionality of this package, especially internal/external file * attributes and extra fields with different layouts for local file * data and central directory entries. * * <p>This class will try to use {@link java.io.RandomAccessFile * RandomAccessFile} when you know that the output is going to go to a * file.</p> * * <p>If RandomAccessFile cannot be used, this implementation will use * a Data Descriptor to store size and CRC information for {@link * #DEFLATED DEFLATED} entries, this means, you don't need to * calculate them yourself.  Unfortunately this is not possible for * the {@link #STORED STORED} method, here setting the CRC and * uncompressed size information is required before {@link * #putNextEntry putNextEntry} can be called.</p> * */public class ZipOutputStream extends FilterOutputStream {    private static final int BYTE_MASK = 0xFF;    private static final int SHORT = 2;    private static final int WORD = 4;    private static final int BUFFER_SIZE = 512;    /**     * Compression method for deflated entries.     *     * @since 1.1     */    public static final int DEFLATED = java.util.zip.ZipEntry.DEFLATED;    /**     * Default compression level for deflated entries.     *     * @since Ant 1.7     */    public static final int DEFAULT_COMPRESSION = Deflater.DEFAULT_COMPRESSION;    /**     * Compression method for stored entries.     *     * @since 1.1     */    public static final int STORED = java.util.zip.ZipEntry.STORED;    /**     * Current entry.     *     * @since 1.1     */    private ZipEntry entry;    /**     * The file comment.     *     * @since 1.1     */    private String comment = "";    /**     * Compression level for next entry.     *     * @since 1.1     */    private int level = DEFAULT_COMPRESSION;    /**     * Has the compression level changed when compared to the last     * entry?     *     * @since 1.5     */    private boolean hasCompressionLevelChanged = false;    /**     * Default compression method for next entry.     *     * @since 1.1     */    private int method = java.util.zip.ZipEntry.DEFLATED;    /**     * List of ZipEntries written so far.     *     * @since 1.1     */    private Vector entries = new Vector();    /**     * CRC instance to avoid parsing DEFLATED data twice.     *     * @since 1.1     */    private CRC32 crc = new CRC32();    /**     * Count the bytes written to out.     *     * @since 1.1     */    private long written = 0;    /**     * Data for local header data     *     * @since 1.1     */    private long dataStart = 0;    /**     * Offset for CRC entry in the local file header data for the     * current entry starts here.     *     * @since 1.15     */    private long localDataStart = 0;    /**     * Start of central directory.     *     * @since 1.1     */    private long cdOffset = 0;    /**     * Length of central directory.     *     * @since 1.1     */    private long cdLength = 0;    /**     * Helper, a 0 as ZipShort.     *     * @since 1.1     */    private static final byte[] ZERO = {0, 0};    /**     * Helper, a 0 as ZipLong.     *     * @since 1.1     */    private static final byte[] LZERO = {0, 0, 0, 0};    /**     * Holds the offsets of the LFH starts for each entry.     *     * @since 1.1     */    private Hashtable offsets = new Hashtable();    /**     * The encoding to use for filenames and the file comment.     *     * <p>For a list of possible values see <a     * href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>.     * Defaults to the platform's default character encoding.</p>     *     * @since 1.3     */    private String encoding = null;    // CheckStyle:VisibilityModifier OFF - bc    /**     * This Deflater object is used for output.     *     * <p>This attribute is only protected to provide a level of API     * backwards compatibility.  This class used to extend {@link     * java.util.zip.DeflaterOutputStream DeflaterOutputStream} up to     * Revision 1.13.</p>     *     * @since 1.14     */    protected Deflater def = new Deflater(level, true);    /**     * This buffer servers as a Deflater.     *     * <p>This attribute is only protected to provide a level of API     * backwards compatibility.  This class used to extend {@link     * java.util.zip.DeflaterOutputStream DeflaterOutputStream} up to     * Revision 1.13.</p>     *     * @since 1.14     */    protected byte[] buf = new byte[BUFFER_SIZE];    // CheckStyle:VisibilityModifier ON    /**     * Optional random access output.     *     * @since 1.14     */    private RandomAccessFile raf = null;    /**     * Creates a new ZIP OutputStream filtering the underlying stream.     * @param out the outputstream to zip     * @since 1.1     */    public ZipOutputStream(OutputStream out) {        super(out);    }    /**     * Creates a new ZIP OutputStream writing to a File.  Will use     * random access if possible.     * @param file the file to zip to     * @since 1.14     * @throws IOException on error     */    public ZipOutputStream(File file) throws IOException {        super(null);        try {            raf = new RandomAccessFile(file, "rw");            raf.setLength(0);        } catch (IOException e) {            if (raf != null) {                try {                    raf.close();                } catch (IOException inner) {                    // ignore                }                raf = null;            }            out = new FileOutputStream(file);        }    }    /**     * This method indicates whether this archive is writing to a seekable stream (i.e., to a random     * access file).     *     * <p>For seekable streams, you don't need to calculate the CRC or     * uncompressed size for {@link #STORED} entries before     * invoking {@link #putNextEntry}.     * @return true if seekable     * @since 1.17     */    public boolean isSeekable() {        return raf != null;    }    /**     * The encoding to use for filenames and the file comment.     *     * <p>For a list of possible values see <a     * href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>.     * Defaults to the platform's default character encoding.</p>     * @param encoding the encoding value     * @since 1.3     */    public void setEncoding(String encoding) {        this.encoding = encoding;    }    /**     * The encoding to use for filenames and the file comment.     *     * @return null if using the platform's default character encoding.     *     * @since 1.3     */    public String getEncoding() {        return encoding;    }    /**     * Finishs writing the contents and closes this as well as the     * underlying stream.     *     * @since 1.1     * @throws IOException on error     */    public void finish() throws IOException {        closeEntry();        cdOffset = written;        for (int i = 0, entriesSize = entries.size(); i < entriesSize; i++) {            writeCentralFileHeader((ZipEntry) entries.elementAt(i));        }        cdLength = written - cdOffset;        writeCentralDirectoryEnd();        offsets.clear();        entries.removeAllElements();    }    /**     * Writes all necessary data for this entry.     *     * @since 1.1     * @throws IOException on error     */    public void closeEntry() throws IOException {        if (entry == null) {            return;        }        long realCrc = crc.getValue();        crc.reset();        if (entry.getMethod() == DEFLATED) {            def.finish();            while (!def.finished()) {                deflate();            }            entry.setSize(adjustToLong(def.getTotalIn()));            entry.setCompressedSize(adjustToLong(def.getTotalOut()));            entry.setCrc(realCrc);            def.reset();            written += entry.getCompressedSize();        } else if (raf == null) {            if (entry.getCrc() != realCrc) {                throw new ZipException("bad CRC checksum for entry "                                       + entry.getName() + ": "                                       + Long.toHexString(entry.getCrc())                                       + " instead of "                                       + Long.toHexString(realCrc));            }            if (entry.getSize() != written - dataStart) {                throw new ZipException("bad size for entry "                                       + entry.getName() + ": "                                       + entry.getSize()                                       + " instead of "                                       + (written - dataStart));            }        } else { /* method is STORED and we used RandomAccessFile */            long size = written - dataStart;            entry.setSize(size);            entry.setCompressedSize(size);            entry.setCrc(realCrc);        }        // If random access output, write the local file header containing        // the correct CRC and compressed/uncompressed sizes        if (raf != null) {            long save = raf.getFilePointer();            raf.seek(localDataStart);            writeOut(ZipLong.getBytes(entry.getCrc()));            writeOut(ZipLong.getBytes(entry.getCompressedSize()));            writeOut(ZipLong.getBytes(entry.getSize()));            raf.seek(save);        }        writeDataDescriptor(entry);        entry = null;    }    /**     * Begin writing next entry.     * @param ze the entry to write     * @since 1.1     * @throws IOException on error     */    public void putNextEntry(ZipEntry ze) throws IOException {        closeEntry();        entry = ze;        entries.addElement(entry);        if (entry.getMethod() == -1) { // not specified            entry.setMethod(method);        }        if (entry.getTime() == -1) { // not specified            entry.setTime(System.currentTimeMillis());        }        // Size/CRC not required if RandomAccessFile is used        if (entry.getMethod() == STORED && raf == null) {            if (entry.getSize() == -1) {                throw new ZipException("uncompressed size is required for"                                       + " STORED method when not writing to a"                                       + " file");            }            if (entry.getCrc() == -1) {                throw new ZipException("crc checksum is required for STORED"                                       + " method when not writing to a file");            }            entry.setCompressedSize(entry.getSize());        }        if (entry.getMethod() == DEFLATED && hasCompressionLevelChanged) {            def.setLevel(level);            hasCompressionLevelChanged = false;        }        writeLocalFileHeader(entry);    }    /**     * Set the file comment.     * @param comment the comment     * @since 1.1     */    public void setComment(String comment) {        this.comment = comment;    }    /**     * Sets the compression level for subsequent entries.     *     * <p>Default is Deflater.DEFAULT_COMPRESSION.</p>     * @param level the compression level.     * @throws IllegalArgumentException if an invalid compression level is specified.     * @since 1.1     */    public void setLevel(int level) {        if (level < Deflater.DEFAULT_COMPRESSION            || level > Deflater.BEST_COMPRESSION) {            throw new IllegalArgumentException(                "Invalid compression level: " + level);        }        hasCompressionLevelChanged = (this.level != level);        this.level = level;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -