Java tutorial
/* * Copyright 2016 DiffPlug * * Licensed 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 com.diffplug.gradle; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.function.Function; import java.util.function.Predicate; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import org.apache.commons.io.IOUtils; import com.diffplug.common.base.Errors; import com.diffplug.common.base.StringPrinter; import com.diffplug.common.base.Throwing; import com.diffplug.common.io.ByteSink; import com.diffplug.common.io.ByteSource; import com.diffplug.common.io.ByteStreams; /** Utilities for mucking with zip files. */ public class ZipMisc { /** * Reads the given entry from the zip. * * @param input a zip file * @param toRead a path within that zip file * @param reader will be called with an InputStream containing the contents of that entry in the zip file */ public static void read(File input, String toRead, Throwing.Specific.Consumer<InputStream, IOException> reader) throws IOException { try (ZipFile file = new ZipFile(input); InputStream stream = file.getInputStream(file.getEntry(toRead));) { reader.accept(stream); } } /** * Reads the given entry from the zip. * * @param input a zip file * @param toRead a path within that zip file * @return the given path within the zip file decoded as a UTF8 string, with only unix newlines. */ public static String read(File input, String toRead) throws IOException { String raw = StringPrinter.buildString(Errors.rethrow().wrap(printer -> { read(input, toRead, inputStream -> { copy(inputStream, printer.toOutputStream(StandardCharsets.UTF_8)); }); })); return FileMisc.toUnixNewline(raw); } /** * Modifies only the specified entries in a zip file. * * @param input a source from a zip file * @param output an output to a zip file * @param toModify a map from path to an input stream for the entries you'd like to change * @param toOmit a set of entries you'd like to leave out of the zip * @throws IOException */ public static void modify(ByteSource input, ByteSink output, Map<String, Function<byte[], byte[]>> toModify, Predicate<String> toOmit) throws IOException { try (ZipInputStream zipInput = new ZipInputStream(input.openBufferedStream()); ZipOutputStream zipOutput = new ZipOutputStream(output.openBufferedStream())) { while (true) { // read the next entry ZipEntry entry = zipInput.getNextEntry(); if (entry == null) { break; } Function<byte[], byte[]> replacement = toModify.get(entry.getName()); if (replacement != null) { byte[] clean = ByteStreams.toByteArray(zipInput); byte[] modified = replacement.apply(clean); // if it's the entry being modified, enter the modified stuff try (InputStream replacementStream = new ByteArrayInputStream(modified)) { ZipEntry newEntry = new ZipEntry(entry.getName()); newEntry.setComment(entry.getComment()); newEntry.setExtra(entry.getExtra()); newEntry.setMethod(entry.getMethod()); newEntry.setTime(entry.getTime()); zipOutput.putNextEntry(newEntry); copy(replacementStream, zipOutput); } } else if (!toOmit.test(entry.getName())) { // if it isn't being modified, just copy the file stream straight-up ZipEntry newEntry = new ZipEntry(entry); newEntry.setCompressedSize(-1); zipOutput.putNextEntry(newEntry); copy(zipInput, zipOutput); } // close the entries zipInput.closeEntry(); zipOutput.closeEntry(); } } } /** * Creates a single-entry zip file. * * @param input an uncompressed file * @param pathWithinArchive the path within the archive * @param output the new zip file it will be compressed into */ public static void zip(File input, String pathWithinArchive, File output) throws IOException { try (ZipOutputStream zipStream = new ZipOutputStream( new BufferedOutputStream(new FileOutputStream(output)))) { zipStream.setMethod(ZipOutputStream.DEFLATED); zipStream.setLevel(9); zipStream.putNextEntry(new ZipEntry(pathWithinArchive)); try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(input))) { copy(inputStream, zipStream); } } } /** Copies one stream into the other. */ private static void copy(InputStream input, OutputStream output) throws IOException { IOUtils.copy(input, output); } /** * Unzips a directory to a folder. * * @param input a zip file * @param destinationDir where the zip will be extracted to */ public static void unzip(File input, File destinationDir) throws IOException { try (ZipInputStream zipInput = new ZipInputStream(new BufferedInputStream(new FileInputStream(input)))) { ZipEntry entry; while ((entry = zipInput.getNextEntry()) != null) { File dest = new File(destinationDir, entry.getName()); if (entry.isDirectory()) { FileMisc.mkdirs(dest); } else { FileMisc.mkdirs(dest.getParentFile()); try (OutputStream output = new BufferedOutputStream(new FileOutputStream(dest))) { copy(zipInput, output); } } } } } }