You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by bo...@apache.org on 2016/10/12 17:01:31 UTC
[3/3] commons-compress git commit: COMPRESS-327 write zip archives to
arbitrary SeekableByteChannels
COMPRESS-327 write zip archives to arbitrary SeekableByteChannels
Project: http://git-wip-us.apache.org/repos/asf/commons-compress/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-compress/commit/7e35f57a
Tree: http://git-wip-us.apache.org/repos/asf/commons-compress/tree/7e35f57a
Diff: http://git-wip-us.apache.org/repos/asf/commons-compress/diff/7e35f57a
Branch: refs/heads/master
Commit: 7e35f57ae9ba9e716da122dfa0bec418b1e2b6e8
Parents: dec527d
Author: Stefan Bodewig <bo...@apache.org>
Authored: Wed Oct 12 19:01:00 2016 +0200
Committer: Stefan Bodewig <bo...@apache.org>
Committed: Wed Oct 12 19:01:00 2016 +0200
----------------------------------------------------------------------
.../archivers/zip/StreamCompressor.java | 30 +++++++
.../archivers/zip/ZipArchiveOutputStream.java | 91 ++++++++++++--------
2 files changed, 86 insertions(+), 35 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/7e35f57a/src/main/java/org/apache/commons/compress/archivers/zip/StreamCompressor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/StreamCompressor.java b/src/main/java/org/apache/commons/compress/archivers/zip/StreamCompressor.java
index e54781e..218f54a 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/StreamCompressor.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/StreamCompressor.java
@@ -24,6 +24,8 @@ import java.io.DataOutput;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.SeekableByteChannel;
import java.util.zip.CRC32;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
@@ -97,6 +99,18 @@ public abstract class StreamCompressor implements Closeable {
/**
* Create a stream compressor with the given compression level.
*
+ * @param os The SeekableByteChannel to receive output
+ * @param deflater The deflater to use for the compressor
+ * @return A stream compressor
+ * @since 1.13
+ */
+ static StreamCompressor create(final SeekableByteChannel os, final Deflater deflater) {
+ return new SeekableByteChannelCompressor(deflater, os);
+ }
+
+ /**
+ * Create a stream compressor with the given compression level.
+ *
* @param compressionLevel The {@link Deflater} compression level
* @param bs The ScatterGatherBackingStore to receive output
* @return A stream compressor
@@ -307,4 +321,20 @@ public abstract class StreamCompressor implements Closeable {
raf.write(data, offset, length);
}
}
+
+ private static final class SeekableByteChannelCompressor extends StreamCompressor {
+ private final SeekableByteChannel channel;
+
+ public SeekableByteChannelCompressor(final Deflater deflater,
+ final SeekableByteChannel channel) {
+ super(deflater);
+ this.channel = channel;
+ }
+
+ @Override
+ protected final void writeOut(final byte[] data, final int offset, final int length)
+ throws IOException {
+ channel.write(ByteBuffer.wrap(data, offset, length));
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/7e35f57a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
index a184d97..22e924e 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
@@ -23,9 +23,12 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.Files;
+import java.nio.file.StandardOpenOption;
import java.util.Calendar;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -55,11 +58,11 @@ import static org.apache.commons.compress.archivers.zip.ZipShort.putShort;
* 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>This class will try to use {@link
+ * java.nio.channels.SeekableByteChannel} when you know that the
+ * output is going to go to a file.</p>
*
- * <p>If RandomAccessFile cannot be used, this implementation will use
+ * <p>If SeekableByteChannel 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
@@ -71,7 +74,7 @@ import static org.apache.commons.compress.archivers.zip.ZipShort.putShort;
* extensions and thus individual entries and archives larger than 4
* GB or with more than 65536 entries in most cases but explicit
* control is provided via {@link #setUseZip64}. If the stream can not
- * user RandomAccessFile and you try to write a ZipArchiveEntry of
+ * use SeekableByteChannel and you try to write a ZipArchiveEntry of
* unknown size then Zip64 extensions will be disabled by default.</p>
*
* @NotThreadSafe
@@ -230,7 +233,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
/**
* Optional random access output.
*/
- private final RandomAccessFile raf;
+ private final SeekableByteChannel channel;
private final OutputStream out;
@@ -268,7 +271,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
*/
public ZipArchiveOutputStream(final OutputStream out) {
this.out = out;
- this.raf = null;
+ this.channel = null;
def = new Deflater(level, true);
streamCompressor = StreamCompressor.create(out, def);
}
@@ -280,20 +283,38 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
* @throws IOException on error
*/
public ZipArchiveOutputStream(final File file) throws IOException {
+ def = new Deflater(level, true);
OutputStream o = null;
- RandomAccessFile _raf = null;
+ SeekableByteChannel _channel = null;
+ StreamCompressor _streamCompressor = null;
try {
- _raf = new RandomAccessFile(file, "rw");
- _raf.setLength(0);
+ _channel = Files.newByteChannel(file.toPath(),
+ EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE,
+ StandardOpenOption.READ,
+ StandardOpenOption.TRUNCATE_EXISTING));
+ _streamCompressor = StreamCompressor.create(_channel, def);
} catch (final IOException e) {
- IOUtils.closeQuietly(_raf);
- _raf = null;
+ IOUtils.closeQuietly(_channel);
+ _channel = null;
o = new FileOutputStream(file);
+ _streamCompressor = StreamCompressor.create(o, def);
}
- def = new Deflater(level, true);
- streamCompressor = StreamCompressor.create(_raf, def);
out = o;
- raf = _raf;
+ channel = _channel;
+ streamCompressor = _streamCompressor;
+ }
+
+ /**
+ * Creates a new ZIP OutputStream writing to a SeekableByteChannel.
+ * @param channel the channel to zip to
+ * @throws IOException on error
+ * @since 1.13
+ */
+ public ZipArchiveOutputStream(SeekableByteChannel channel) throws IOException {
+ this.channel = channel;
+ def = new Deflater(level, true);
+ streamCompressor = StreamCompressor.create(channel, def);
+ out = null;
}
/**
@@ -306,7 +327,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
* @return true if seekable
*/
public boolean isSeekable() {
- return raf != null;
+ return channel != null;
}
/**
@@ -506,7 +527,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
}
private void closeEntry(final boolean actuallyNeedsZip64, final boolean phased) throws IOException {
- if (!phased && raf != null) {
+ if (!phased && channel != null) {
rewriteSizesAndCrc(actuallyNeedsZip64);
}
@@ -585,7 +606,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
entry.entry.setCompressedSize(bytesWritten);
entry.entry.setCrc(crc);
- } else if (raf == null) {
+ } else if (channel == null) {
if (entry.entry.getCrc() != crc) {
throw new ZipException("bad CRC checksum for entry "
+ entry.entry.getName() + ": "
@@ -640,9 +661,9 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
*/
private void rewriteSizesAndCrc(final boolean actuallyNeedsZip64)
throws IOException {
- final long save = raf.getFilePointer();
+ final long save = channel.position();
- raf.seek(entry.localDataStart);
+ channel.position(entry.localDataStart);
writeOut(ZipLong.getBytes(entry.entry.getCrc()));
if (!hasZip64Extra(entry.entry) || !actuallyNeedsZip64) {
writeOut(ZipLong.getBytes(entry.entry.getCompressedSize()));
@@ -656,8 +677,8 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
final ByteBuffer name = getName(entry.entry);
final int nameLen = name.limit() - name.position();
// seek to ZIP64 extra, skip header and size information
- raf.seek(entry.localDataStart + 3 * WORD + 2 * SHORT
- + nameLen + 2 * SHORT);
+ channel.position(entry.localDataStart + 3 * WORD + 2 * SHORT
+ + nameLen + 2 * SHORT);
// inside the ZIP64 extra uncompressed size comes
// first, unlike the LFH, CD or data descriptor
writeOut(ZipEightByteInteger.getBytes(entry.entry.getSize()));
@@ -666,7 +687,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
if (!actuallyNeedsZip64) {
// do some cleanup:
// * rewrite version needed to extract
- raf.seek(entry.localDataStart - 5 * SHORT);
+ channel.position(entry.localDataStart - 5 * SHORT);
writeOut(ZipShort.getBytes(INITIAL_VERSION));
// * remove ZIP64 extra so it doesn't get written
@@ -682,7 +703,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
}
}
}
- raf.seek(save);
+ channel.position(save);
}
/**
@@ -778,7 +799,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
private void validateSizeInformation(final Zip64Mode effectiveMode)
throws ZipException {
// Size/CRC not required if RandomAccessFile is used
- if (entry.entry.getMethod() == STORED && raf == null) {
+ if (entry.entry.getMethod() == STORED && channel == null) {
if (entry.entry.getSize() == ArchiveEntry.SIZE_UNKNOWN) {
throw new ZipException("uncompressed size is required for"
+ " STORED method when not writing to a"
@@ -818,7 +839,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
|| entry.getSize() >= ZIP64_MAGIC
|| entry.getCompressedSize() >= ZIP64_MAGIC
|| (entry.getSize() == ArchiveEntry.SIZE_UNKNOWN
- && raf != null && mode != Zip64Mode.Never);
+ && channel != null && mode != Zip64Mode.Never);
}
/**
@@ -1036,7 +1057,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
// CRC
if (phased){
putLong(ze.getCrc(), buf, LFH_CRC_OFFSET);
- } else if (zipMethod == DEFLATED || raf != null) {
+ } else if (zipMethod == DEFLATED || channel != null) {
System.arraycopy(LZERO, 0, buf, LFH_CRC_OFFSET, WORD);
} else {
putLong(ze.getCrc(), buf, LFH_CRC_OFFSET);
@@ -1053,7 +1074,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
} else if (phased) {
putLong(ze.getCompressedSize(), buf, LFH_COMPRESSED_SIZE_OFFSET);
putLong(ze.getSize(), buf, LFH_ORIGINAL_SIZE_OFFSET);
- } else if (zipMethod == DEFLATED || raf != null) {
+ } else if (zipMethod == DEFLATED || channel != null) {
System.arraycopy(LZERO, 0, buf, LFH_COMPRESSED_SIZE_OFFSET, WORD);
System.arraycopy(LZERO, 0, buf, LFH_ORIGINAL_SIZE_OFFSET, WORD);
} else { // Stored
@@ -1115,7 +1136,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
* @throws IOException on error
*/
protected void writeDataDescriptor(final ZipArchiveEntry ze) throws IOException {
- if (ze.getMethod() != DEFLATED || raf != null) {
+ if (ze.getMethod() != DEFLATED || channel != null) {
return;
}
writeCounted(DD_SIG);
@@ -1436,7 +1457,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
}
private boolean isDeflatedToOutputStream(final int zipMethod) {
- return zipMethod == DEFLATED && raf == null;
+ return zipMethod == DEFLATED && channel == null;
}
@@ -1481,7 +1502,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
System.err.println("Adding z64 for " + ze.getName()
+ ", method: " + ze.getMethod()
+ " (" + (ze.getMethod() == STORED) + ")"
- + ", raf: " + (raf != null));
+ + ", channel: " + (channel != null));
*/
z64 = new Zip64ExtendedInformationExtraField();
}
@@ -1513,7 +1534,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
*/
private Zip64Mode getEffectiveZip64Mode(final ZipArchiveEntry ze) {
if (zip64Mode != Zip64Mode.AsNeeded
- || raf != null
+ || channel != null
|| ze.getMethod() != DEFLATED
|| ze.getSize() != ArchiveEntry.SIZE_UNKNOWN) {
return zip64Mode;
@@ -1539,8 +1560,8 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream {
* corrupt archives so they can clean up any temporary files.</p>
*/
void destroy() throws IOException {
- if (raf != null) {
- raf.close();
+ if (channel != null) {
+ channel.close();
}
if (out != null) {
out.close();