X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Futil%2FFileUtils.java;h=7e607ab2936fc99498906b19b0a9b074085f9cc3;hb=57447cbc359ed9a0c8826540079898677ef86660;hp=1684763e6822be31ef41d25ac39e266277a496d0;hpb=ff638b98db095ffd7dc792f5d91fe5a0de6fc2ba;p=jalview.git diff --git a/src/jalview/util/FileUtils.java b/src/jalview/util/FileUtils.java index 1684763..7e607ab 100644 --- a/src/jalview/util/FileUtils.java +++ b/src/jalview/util/FileUtils.java @@ -2,6 +2,15 @@ package jalview.util; import java.io.File; import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; /** * Miscellaneous file-related functions @@ -75,4 +84,125 @@ public final class FileUtils return f; } + /** + * Answers a (possibly empty) list of file paths found by searching below + * from that match the supplied regular expression + * pattern. Results may include from itself if it + * matches. If an exception occurs it is written to syserr and any results up to + * that point are returned. Note that the regular expression match applies to + * the whole path of any matched file. + *

+ * WARNING: because the whole directory tree below from is + * searched, this method may be slow if used for a high level directory, or may + * exit prematurely if security or other exceptions occur. + * + *

+   * Example: 
+   *   findMatchingPaths(Paths.get("C:/Program Files"), ".*/chimera.exe$")
+   * 
+ * + * @param from + * @param pattern + * + * @return + * @see https://stackoverflow.com/questions/794381/how-to-find-files-that-match-a-wildcard-string-in-java/31685610#comment62441832_31685610 + */ + public static List findMatchingPaths(Path from, String pattern) + { + List matches = new ArrayList<>(); + PathMatcher pathMatcher = FileSystems.getDefault() + .getPathMatcher("regex:" + pattern); + try + { + Files.walk(from).filter(pathMatcher::matches) + .forEach(m -> matches.add(m.toString())); + } catch (IOException e) + { + System.err.println( + "Error searching for " + pattern + " : " + e.toString()); + } + + return matches; + } + + /** + * Answers a (possibly empty) list of paths to files below the given root path, + * that match the given pattern. The pattern should be a '/' delimited set of + * glob patterns, each of which is used to match child file names (not full + * paths). Note that 'directory spanning' glob patterns (**) are not + * supported by this method. + *

+ * For example + * + *

+   *   findMatches("C:\\", "Program Files*/Chimera*/bin/{chimera,chimera.exe}"
+   * 
+ * + * would match "C:\Program Files\Chimera 1.11\bin\chimera.exe" and "C:\Program + * Files (x86)\Chimera 1.10.1\bin\chimera" + * + * @param root + * @param pattern + * @return + * @see https://docs.oracle.com/javase/tutorial/essential/io/fileOps.html#glob + */ + public static List findMatches(String root, String pattern) + { + List results = new ArrayList<>(); + try + { + Path from = Paths.get(root); + findMatches(results, from, Arrays.asList(pattern.split("/"))); + } catch (Throwable e) + { + // Paths.get can throw IllegalArgumentException + System.err.println(String.format("Error searching %s for %s: %s", + root, pattern, e.toString())); + } + + return results; + } + + /** + * A helper method that performs recursive search of file patterns and adds any + * 'leaf node' matches to the results list + * + * @param results + * @param from + * @param patterns + */ + protected static void findMatches(List results, Path from, + List patterns) + { + if (patterns.isEmpty()) + { + /* + * reached end of recursion with all components matched + */ + results.add(from.toString()); + return; + } + + String pattern = patterns.get(0); + try (DirectoryStream dirStream = Files.newDirectoryStream(from, + pattern)) + { + dirStream.forEach(p -> { + + /* + * matched a next level file - search below it + * (ignore non-directory non-leaf matches) + */ + List subList = patterns.subList(1, patterns.size()); + if (subList.isEmpty() || p.toFile().isDirectory()) + { + findMatches(results, p, subList); + } + }); + } catch (IOException e) + { + System.err.println(String.format("Error searching %s: %s", pattern, + e.toString())); + } + } }