package de.uni_passau.fim.infosun.prophet.plugin.plugins.mailPlugin; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.URI; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; import java.util.Optional; import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; /** * A <code>File</code> that can be zipped. */ public class ZFile extends File { private static final String EXTENSION = ".zip"; /** * See {@link File#File(String)} for documentation. * * @param pathname * A pathname string * * @throws NullPointerException * If the <code>pathname</code> argument is <code>null</code> */ public ZFile(String pathname) { super(pathname); } /** * See {@link File#File(String, String)} for documentation. * * @param parent * The parent pathname string * @param child * The child pathname string * * @throws NullPointerException * If <code>child</code> is <code>null</code> */ public ZFile(String parent, String child) { super(parent, child); } /** * See {@link File#File(File, String)} for documentation. * * @param parent * The parent abstract pathname * @param child * The child pathname string * * @throws NullPointerException * If <code>child</code> is <code>null</code> */ public ZFile(File parent, String child) { super(parent, child); } /** * See {@link File#File(URI)} for documentation. * * @param uri * An absolute, hierarchical URI with a scheme equal to * <tt>"file"</tt>, a non-empty path component, and undefined * authority, query, and fragment components * * @throws NullPointerException * If <tt>uri</tt> is <tt>null</tt> * @throws IllegalArgumentException * If the preconditions on the parameter do not hold * @see #toURI() * @see java.net.URI * @since 1.4 */ public ZFile(URI uri) { super(uri); } /** * Zips this file and stores the resulting archive in its parent directory. * The archive will have the same name as this <code>File</code>. * This method will do nothing (except print a warning) for files without a parent. * * @return optionally the created archive <code>File</code> */ public Optional<File> zip() { File parent = getParentFile(); if (parent == null) { System.err.println("Aborting zip of " + getAbsolutePath()); System.err.println("Could not find a parent directory to save the archive to. Use zip(toDirectory)."); return Optional.empty(); } else { return zip(parent); } } /** * Zips this file and stores the resulting archive in the given directory. * <code>toDirectory</code> will be created if it does not exist. * The archive will have the same name as this <code>File</code>. * * @param toDirectory * the directory to save the resulting archive in * * @return optionally the created archive <code>File</code> * * @throws IllegalArgumentException * if <code>toDirectory</code> exists and is not a directory */ public Optional<File> zip(File toDirectory) { return zip(toDirectory, checkArchiveName(getName())); } /** * Zips this file and stores the resulting archive in the given directory. * <code>toDirectory</code> will be created if it does not exist. * * @param toDirectory * the directory to save the resulting archive in * @param withName * the name for the archive (without extension) * * @return optionally the created archive <code>File</code> * * @throws IllegalArgumentException * if <code>toDirectory</code> exists and is not a directory */ public Optional<File> zip(File toDirectory, String withName) { String archiveName = checkArchiveName(withName); if (!exists()) { System.err.println(getAbsolutePath() + " does not exist and can therefore not be zipped."); return Optional.empty(); } if (toDirectory.exists() && !toDirectory.isDirectory()) { throw new IllegalArgumentException("toDirectory exists and is not a directory."); } if (!toDirectory.exists() && !toDirectory.mkdirs()) { System.err.println("Could not create the target directory " + toDirectory.getAbsolutePath()); return Optional.empty(); } File archiveFile = new File(toDirectory, archiveName); try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(archiveFile))) { try (Stream<Path> stream = Files.walk(toPath())) { stream.forEach(path -> { String name = getName() + '/' + toURI().relativize(path.toUri()).getPath(); try { zipOut.putNextEntry(new ZipEntry(name)); copy(path.toFile(), zipOut); zipOut.closeEntry(); } catch (IOException e) { System.err.println("Could not zip the file " + path); System.err.println(e.getClass().getSimpleName() + " : " + e.getMessage()); } }); } catch (IOException e) { System.err.println("Could not walk the file tree under " + getAbsolutePath()); System.err.println(e.getClass().getSimpleName() + " : " + e.getMessage()); return Optional.empty(); } } catch (FileNotFoundException e) { System.err.println("Could not write the archive file " + archiveFile.getAbsolutePath()); System.err.println(e.getClass().getSimpleName() + " : " + e.getMessage()); return Optional.empty(); } catch (IOException ignored) { // may occur when closing the ZipOutputStream } return Optional.of(archiveFile); } /** * Checks whether a given name ends with ".zip" and appends that suffix if it is missing. * * @param name * the name to check * * @return the resulting name */ private String checkArchiveName(String name) { return name.endsWith(EXTENSION) ? name : name + EXTENSION; } /** * Copies the given <code>File</code> to the <code>OutputStream</code>. Does nothing for directories. * * @param file * the <code>File</code> to be copied * @param outputStream * the <code>OutputStream</code> to be copied to */ private void copy(File file, OutputStream outputStream) { ByteBuffer byteBuffer; FileChannel channel; byte[] buffer; int numRead; if (file.isDirectory()) { return; } try (FileInputStream fis = new FileInputStream(file)) { channel = fis.getChannel(); buffer = new byte[256 * 1024]; byteBuffer = ByteBuffer.wrap(buffer); while ((numRead = channel.read(byteBuffer)) != -1) { outputStream.write(buffer, 0, numRead); byteBuffer.clear(); } } catch (IOException e) { System.err.println("Could not copy " + file.getAbsolutePath() + " to the given OutputStream."); System.err.println(e.getClass().getSimpleName() + ':' + e.getMessage()); } } }