package net.ayld.facade.util; import java.io.File; import java.io.IOException; import java.nio.file.FileVisitOption; import java.nio.file.FileVisitResult; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.Collections; import java.util.Iterator; import java.util.List; import net.ayld.facade.util.annotation.NotThreadSafe; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; /** * OK since I'm currently too lazy to properly document this class, I'm just going to give usage examples. * * Given the following file system tree: * * /root * - anExe.exe * - aDll.dll * - another.dll * /sub * - subExe.exe * - anExe.exe * - subDll.dll * * All {@link Files} methods are recursive by default. * To make them non-recursive just call {@link Files#nonRecursive()} anywhere, like so: * <pre> * <code> Files.in("/root").withExtension("dll").nonRecursive().list(); </code> * <pre> * So to: * <pre> * - list all DLLs in the /root folder recursively: * <pre> * <code>Files.in("/root").withExtension("dll").list();</code> * <pre> * Returns: ["/root/aDll.dll", "/root/another.dll", "/root/sub/subDll.dll"] * <pre> * - list all files named 'anExe' in the /root folder recursively: * <pre> * <code>Files.in("/root").named("anExe").list();</code> * <pre> * Returns: ["/root/anExe.exe", "/root/sub/anExe.exe"] * <pre> * - to list all DLLs in /root AND all files named 'anExe': * <pre> * <code>Files.in("/root").withExtension("dll").named("anExe").inclusive();</code> * <pre> * Returns: ["/root/anExe.exe", "/root/sub/anExe.exe", "/root/aDll.dll", "/root/another.dll", "/root/sub/subDll.dll"] * <pre> * Note: <code>Files.in("/root").withExtension("dll").named("anExe").exclusive();</code> * <pre> * Will return nothing since there are no files named 'anExe' with a extension .dll * <pre> * - to list all files in /root which are named 'subExe' and have the .exe extension: * <pre> * <code>Files.in("/root").withExtension("exe").named("subExe").exclusive();</code> * <pre> * Returns: ["/root/anExe.exe", "/root/sub/anExe.exe"] * <pre> * This should be enough for you :) * * */ @NotThreadSafe public final class Files { // XXX this is actually rather procedural ... private static final String FILE_EXTENSION_DELIMITER = "."; private final File dir; private boolean recursive = true; private List<File> result = Lists.newLinkedList(); private String requiredName; private String requiredExtension; private Files(File dir) { this.dir = dir; } public static Files in(String dir) { final File directory = new File(dir); if (!directory.isDirectory()) { throw new IllegalArgumentException(dir + " is not a directory"); } return new Files(directory); } public Files nonRecursive() { this.recursive = false; return this; } public List<File> list() { return inclusive(); } public File single() { result = exclusive(); if (result.isEmpty()) { throw new IllegalStateException("no files with name: " + requiredName + " and extension: " + requiredExtension + " found in " + dir.getAbsolutePath()); } if (result.size() > 1) { throw new IllegalStateException("can not return singular file with given query, currently found: " + result); } return result.iterator().next(); } public List<File> exclusive() { final Iterator<File> resultIter = result.iterator(); if (!Strings.isNullOrEmpty(requiredName)) { while (resultIter.hasNext()) { final File file = resultIter.next(); final String name = file.getName(); final String nameNoExtension = Tokenizer.delimiter(FILE_EXTENSION_DELIMITER) .tokenize(name) .firstToken(); if (!nameNoExtension.equalsIgnoreCase(requiredName)) { resultIter.remove(); } } } if (!Strings.isNullOrEmpty(requiredExtension)) { while (resultIter.hasNext()) { final File file = resultIter.next(); final String extension = Tokenizer.delimiter(FILE_EXTENSION_DELIMITER) .tokenize(file.getAbsolutePath()) .lastToken(); if (!extension.equalsIgnoreCase(requiredExtension)) { resultIter.remove(); } } } return ImmutableList.copyOf(result); } public List<File> inclusive() { return ImmutableList.copyOf(result); } public List<File> all() throws IOException { if (!Strings.isNullOrEmpty(requiredName) || !Strings.isNullOrEmpty(requiredExtension)) { return inclusive(); } final int recursionDepth = recursive ? Integer.MAX_VALUE : 1; java.nio.file.Files.walkFileTree(Paths.get(dir.getAbsolutePath()), Collections.<FileVisitOption>emptySet(), recursionDepth, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { final File file = path.toFile(); if (file.isFile()) { result.add(file); } return FileVisitResult.CONTINUE; } }); return ImmutableList.copyOf(result); } public Files named(final String name) throws IOException { requiredName = name; final List<File> result = Lists.newLinkedList(); final int recursionDepth = recursive ? Integer.MAX_VALUE : 1; java.nio.file.Files.walkFileTree(Paths.get(dir.getAbsolutePath()), Collections.<FileVisitOption>emptySet(), recursionDepth, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { final String filename = path.getFileName().toString(); final String filenameNoExtension = Tokenizer.delimiter(FILE_EXTENSION_DELIMITER).tokenize(filename).firstToken(); if (filenameNoExtension.equalsIgnoreCase(name)) { result.add(path.toFile()); } return FileVisitResult.CONTINUE; } }); this.result.addAll(ImmutableList.copyOf(result)); return this; } public Files withExtension(final String ext) throws IOException { requiredExtension = ext; final List<File> result = Lists.newLinkedList(); final int recursionDepth = recursive ? Integer.MAX_VALUE : 1; java.nio.file.Files.walkFileTree(Paths.get(dir.getAbsolutePath()), Collections.<FileVisitOption>emptySet(), recursionDepth, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { final String filepath = path.getFileName().toString(); final String fileExtension = Tokenizer.delimiter(FILE_EXTENSION_DELIMITER).tokenize(filepath).lastToken(); if (fileExtension.equals(ext)) { result.add(path.toFile()); } return FileVisitResult.CONTINUE; } }); this.result.addAll(ImmutableList.copyOf(result)); return this; } public static void deleteRecursive(File file) throws IOException { if (file == null || !file.exists()) { return; } if (file.isDirectory()) { for (File sub : file.listFiles()) { deleteRecursive(sub); } } if (!file.delete()) { throw new IOException("failed to deleteRecursive: " + file); } } }