4 import java.io.IOException;
5 import java.nio.file.DirectoryStream;
6 import java.nio.file.FileSystems;
7 import java.nio.file.Files;
8 import java.nio.file.Path;
9 import java.nio.file.PathMatcher;
10 import java.nio.file.Paths;
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.List;
16 * Miscellaneous file-related functions
18 public final class FileUtils
22 * Answers the executable file for the given command, or null if not found or
23 * not executable. The path to the executable is the command name prefixed by
24 * the given folder path, optionally with .exe appended.
27 * command short name, for example hmmbuild
29 * parent folder for the executable
32 public static File getExecutable(String cmd, String binaryPath)
34 File file = new File(binaryPath, cmd);
35 if (!file.canExecute())
37 file = new File(binaryPath, cmd + ".exe");
39 if (!file.canExecute())
49 * Answers the path to the folder containing the given executable file, by
50 * searching the PATH environment variable. Answers null if no such executable
56 public static String getPathTo(String cmd)
58 String paths = System.getenv("PATH");
59 // backslash is to escape regular expression argument
60 for (String path : paths.split("\\" + File.pathSeparator))
62 if (getExecutable(cmd, path) != null)
71 * A convenience method to create a temporary file that is deleted on exit of
79 public static File createTempFile(String prefix, String suffix)
82 File f = File.createTempFile(prefix, suffix);
88 * Answers a (possibly empty) list of file paths found by searching below
89 * <code>from</code> that match the supplied regular expression
90 * <code>pattern</code>. Results may include <code>from</code> itself if it
91 * matches. If an exception occurs it is written to syserr and any results up to
92 * that point are returned. Note that the regular expression match applies to
93 * the whole path of any matched file.
95 * WARNING: because the whole directory tree below <code>from</code> is
96 * searched, this method may be slow if used for a high level directory, or may
97 * exit prematurely if security or other exceptions occur.
101 * findMatchingPaths(Paths.get("C:/Program Files"), ".*/chimera.exe$")
108 * @see https://stackoverflow.com/questions/794381/how-to-find-files-that-match-a-wildcard-string-in-java/31685610#comment62441832_31685610
110 public static List<String> findMatchingPaths(Path from, String pattern)
112 List<String> matches = new ArrayList<>();
113 PathMatcher pathMatcher = FileSystems.getDefault()
114 .getPathMatcher("regex:" + pattern);
117 Files.walk(from).filter(pathMatcher::matches)
118 .forEach(m -> matches.add(m.toString()));
119 } catch (IOException e)
122 "Error searching for " + pattern + " : " + e.toString());
129 * Answers a (possibly empty) list of paths to files below the given root path,
130 * that match the given pattern. The pattern should be a '/' delimited set of
131 * glob patterns, each of which is used to match child file names (not full
132 * paths). Note that 'directory spanning' glob patterns (**) are <em>not</em>
133 * supported by this method.
138 * findMatches("C:\\", "Program Files*/Chimera*/bin/{chimera,chimera.exe}"
141 * would match "C:\Program Files\Chimera 1.11\bin\chimera.exe" and "C:\Program
142 * Files (x86)\Chimera 1.10.1\bin\chimera"
147 * @see https://docs.oracle.com/javase/tutorial/essential/io/fileOps.html#glob
149 public static List<String> findMatches(String root, String pattern)
151 List<String> results = new ArrayList<>();
154 Path from = Paths.get(root);
155 findMatches(results, from, Arrays.asList(pattern.split("/")));
156 } catch (Throwable e)
158 // Paths.get can throw IllegalArgumentException
159 System.err.println(String.format("Error searching %s for %s: %s",
160 root, pattern, e.toString()));
167 * A helper method that performs recursive search of file patterns and adds any
168 * 'leaf node' matches to the results list
174 protected static void findMatches(List<String> results, Path from,
175 List<String> patterns)
177 if (patterns.isEmpty())
180 * reached end of recursion with all components matched
182 results.add(from.toString());
186 String pattern = patterns.get(0);
187 try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(from,
190 dirStream.forEach(p -> {
193 * matched a next level file - search below it
194 * (ignore non-directory non-leaf matches)
196 List<String> subList = patterns.subList(1, patterns.size());
197 if (subList.isEmpty() || p.toFile().isDirectory())
199 findMatches(results, p, subList);
202 } catch (IOException e)
204 System.err.println(String.format("Error searching %s: %s", pattern,