4 import java.io.IOException;
5 import java.nio.file.FileSystems;
6 import java.nio.file.FileVisitOption;
7 import java.nio.file.FileVisitResult;
8 import java.nio.file.Files;
9 import java.nio.file.Path;
10 import java.nio.file.PathMatcher;
11 import java.nio.file.Paths;
12 import java.nio.file.SimpleFileVisitor;
13 import java.nio.file.attribute.BasicFileAttributes;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.EnumSet;
17 import java.util.List;
18 import java.util.stream.Collectors;
20 import jalview.bin.Console;
22 public class FileUtils
25 * Given string glob pattern (see
26 * https://docs.oracle.com/javase/7/docs/api/java/nio/file/FileSystem.html#getPathMatcher(java.lang.String)
27 * ) return a List of Files that match the pattern.
28 * Note this is a java style glob, not necessarily a bash-style glob, though there are sufficient similarities.
30 public static List<File> getFilesFromGlob(String pattern)
32 return getFilesFromGlob(pattern, true);
35 public static List<File> getFilesFromGlob(String pattern,
36 boolean allowSingleFilenameThatDoesNotExist)
38 pattern = substituteHomeDir(pattern);
39 String relativePattern = pattern.startsWith(File.separator) ? null
41 List<File> files = new ArrayList<>();
43 * For efficiency of the Files.walkFileTree(), let's find the longest path that doesn't need globbing.
44 * We look for the first glob character * { ? and then look for the last File.separator before that.
45 * Then we can reset the path to look at and shorten the globbing pattern.
46 * Relative paths can be used in pattern, which work from the pwd (though these are converted into
47 * full paths in the match).
49 int firstGlobChar = -1;
50 boolean foundGlobChar = false;
51 for (char c : new char[] { '*', '{', '?' })
53 if (pattern.indexOf(c) > -1
54 && (pattern.indexOf(c) < firstGlobChar || !foundGlobChar))
56 firstGlobChar = pattern.indexOf(c);
60 int lastFS = pattern.lastIndexOf(File.separatorChar, firstGlobChar);
63 String pS = pattern.substring(0, lastFS + 1);
64 String rest = pattern.substring(lastFS + 1);
69 Path parentDir = Paths.get(pS);
70 if (parentDir.toFile().exists())
74 String glob = "glob:" + parentDir.toString() + File.separator
76 PathMatcher pm = FileSystems.getDefault().getPathMatcher(glob);
77 int maxDepth = rest.contains("**") ? 1028
79 .filter(ch -> ch == File.separatorChar).count())
82 Files.walkFileTree(parentDir,
83 EnumSet.of(FileVisitOption.FOLLOW_LINKS), maxDepth,
84 new SimpleFileVisitor<Path>()
87 public FileVisitResult visitFile(Path path,
88 BasicFileAttributes attrs) throws IOException
92 files.add(path.toFile());
94 return FileVisitResult.CONTINUE;
98 public FileVisitResult visitFileFailed(Path file,
99 IOException exc) throws IOException
101 return FileVisitResult.CONTINUE;
104 } catch (IOException e)
113 File f = new File(pattern);
114 if (allowSingleFilenameThatDoesNotExist || f.exists())
119 Collections.sort(files);
124 public static List<String> getFilenamesFromGlob(String pattern)
126 // convert list of Files to list of File.getPath() Strings
127 return getFilesFromGlob(pattern).stream().map(f -> f.getPath())
128 .collect(Collectors.toList());
131 public static String substituteHomeDir(String path)
133 return path.startsWith("~" + File.separator)
134 ? System.getProperty("user.home") + path.substring(1)
139 * This method returns the basename of File file
141 public static String getBasename(File file)
143 return getBasenameOrExtension(file, false);
147 * This method returns the extension of File file.
149 public static String getExtension(File file)
151 return getBasenameOrExtension(file, true);
154 public static String getBasenameOrExtension(File file, boolean extension)
160 String filename = file.getName();
161 int lastDot = filename.lastIndexOf('.');
162 if (lastDot > 0) // don't truncate if starts with '.'
164 value = extension ? filename.substring(lastDot + 1)
165 : filename.substring(0, lastDot);
169 value = extension ? "" : filename;
175 * This method returns the dirname of the first --append or --open value.
176 * Used primarily for substitutions in output filenames.
178 public static String getDirname(File file)
183 String dirname = null;
184 File p = file.getParentFile();
189 File d = new File(substituteHomeDir(p.getPath()));
190 dirname = d.getPath();
194 public static String convertWildcardsToPath(String value, String wildcard,
195 String dirname, String basename)
201 StringBuilder path = new StringBuilder();
202 int lastFileSeparatorIndex = value.lastIndexOf(File.separatorChar);
203 int wildcardBeforeIndex = value.indexOf(wildcard);
204 if (lastFileSeparatorIndex > wildcard.length() - 1
205 && wildcardBeforeIndex < lastFileSeparatorIndex)
207 path.append(value.substring(0, wildcardBeforeIndex));
208 path.append(dirname);
209 path.append(value.substring(wildcardBeforeIndex + wildcard.length(),
210 lastFileSeparatorIndex + 1));
214 path.append(value.substring(0, lastFileSeparatorIndex + 1));
216 int wildcardAfterIndex = value.indexOf(wildcard,
217 lastFileSeparatorIndex);
218 if (wildcardAfterIndex > lastFileSeparatorIndex)
220 path.append(value.substring(lastFileSeparatorIndex + 1,
221 wildcardAfterIndex));
222 path.append(basename);
223 path.append(value.substring(wildcardAfterIndex + wildcard.length()));
227 path.append(value.substring(lastFileSeparatorIndex + 1));
229 return path.toString();
232 public static File getParentDir(File file)
238 File parentDir = file.getAbsoluteFile().getParentFile();
242 public static boolean checkParentDir(File file, boolean mkdirs)
248 File parentDir = getParentDir(file);
249 if (parentDir.exists())
251 // already exists, nothing to do so nothing to worry about!
260 Path path = file.toPath();
261 for (int i = 0; i < path.getNameCount(); i++)
263 Path p = path.getName(i);
264 if ("..".equals(p.toString()))
266 Console.warn("Cautiously not running mkdirs on " + file.toString()
267 + " because the path to be made contains '..'");
272 return parentDir.mkdirs();