ZFile implements Closeable { public void add(@NonNull String name, @NonNull InputStream stream) throws IOException { add(name, stream, true); } ZFile(@NonNull File file);  ZFile(@NonNull File file, @NonNull ZFileOptions options); @NonNull Set<StoredEntry> entries(); @Nullable StoredEntry get(@NonNull String path); @NonNull InputStream directOpen(final long start, final long end); void update(); @Override void close(); @NonNull byte[] getCentralDirectoryBytes(); @NonNull byte[] getEocdBytes(); void openReadOnly(); void add(@NonNull String name, @NonNull InputStream stream); void add(@NonNull String name, @NonNull InputStream stream, boolean mayCompress); void mergeFrom(@NonNull ZFile src, @NonNull Predicate<String> ignoreFilter); void touch(); void finishAllBackgroundTasks(); boolean realign(); void addZFileExtension(@NonNull ZFileExtension extension); void removeZFileExtension(@NonNull ZFileExtension extension); void directWrite(long offset, @NonNull byte[] data, int start, int count); void directWrite(long offset, @NonNull byte[] data); int directRead(long offset, @NonNull byte[] data, int start, int count); int directRead(long offset, @NonNull byte[] data); void directFullyRead(long offset, @NonNull byte[] data); void addAllRecursively(@NonNull File file); void addAllRecursively(@NonNull File file,
            @NonNull Function<? super File, Boolean> mayCompress); long getCentralDirectoryOffset(); long getCentralDirectorySize(); long getEocdOffset(); long getEocdSize(); void setExtraDirectoryOffset(long offset); long getExtraDirectoryOffset(); boolean areTimestampsIgnored(); void sortZipContents(); @NonNull File getFile(); static final char SEPARATOR; }
@Test public void zipMemoryUsageIsZeroAfterClose() throws Exception { File zipFile = new File(mTemporaryFolder.getRoot(), "a.zip"); ZFileOptions options = new ZFileOptions(); long used; try (ZFile zip = new ZFile(zipFile, options)) { assertEquals(0, options.getTracker().getBytesUsed()); assertEquals(0, options.getTracker().getMaxBytesUsed()); zip.add("Blah", new ByteArrayInputStream(new byte[500])); used = options.getTracker().getBytesUsed(); assertTrue(used > 500); assertEquals(used, options.getTracker().getMaxBytesUsed()); } assertEquals(0, options.getTracker().getBytesUsed()); assertEquals(used, options.getTracker().getMaxBytesUsed()); }
@Test public void deferredCompression() throws Exception { File zipFile = new File(mTemporaryFolder.getRoot(), "a.zip"); ExecutorService executor = Executors.newSingleThreadExecutor(); ZFileOptions options = new ZFileOptions(); boolean[] done = new boolean[1]; options.setCompressor(new DeflateExecutionCompressor(executor, options.getTracker(), Deflater.BEST_COMPRESSION) { @NonNull @Override protected CompressionResult immediateCompress(@NonNull CloseableByteSource source) throws Exception { Thread.sleep(500); CompressionResult cr = super.immediateCompress(source); done[0] = true; return cr; } }); try (ZFile zip = new ZFile(zipFile, options)) { byte sequences = 100; int seqCount = 1000; byte[] compressableData = new byte[sequences * seqCount]; for (byte i = 0; i < sequences; i++) { for (int j = 0; j < seqCount; j++) { compressableData[i * seqCount + j] = i; } } zip.add("compressedFile", new ByteArrayInputStream(compressableData)); assertFalse(done[0]); long tooLong = System.currentTimeMillis() + 10000; while (!done[0] && System.currentTimeMillis() < tooLong) { Thread.sleep(10); } assertTrue(done[0]); } executor.shutdownNow(); }