2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
24 import java.io.IOException;
25 import java.nio.file.FileSystems;
26 import java.nio.file.FileVisitOption;
27 import java.nio.file.FileVisitResult;
28 import java.nio.file.Files;
29 import java.nio.file.Path;
30 import java.nio.file.PathMatcher;
31 import java.nio.file.Paths;
32 import java.nio.file.SimpleFileVisitor;
33 import java.nio.file.attribute.BasicFileAttributes;
34 import java.util.ArrayList;
35 import java.util.Collections;
36 import java.util.EnumSet;
37 import java.util.List;
38 import java.util.stream.Collectors;
40 import jalview.bin.Console;
42 public class FileUtils
45 * Given string glob pattern (see
46 * https://docs.oracle.com/javase/7/docs/api/java/nio/file/FileSystem.html#getPathMatcher(java.lang.String)
47 * ) return a List of Files that match the pattern.
48 * Note this is a java style glob, not necessarily a bash-style glob, though there are sufficient similarities.
50 public static List<File> getFilesFromGlob(String pattern)
52 return getFilesFromGlob(pattern, true);
55 public static List<File> getFilesFromGlob(String pattern,
56 boolean allowSingleFilenameThatDoesNotExist)
58 pattern = substituteHomeDir(pattern);
59 String relativePattern = pattern.startsWith(File.separator) ? null
61 List<File> files = new ArrayList<>();
63 * For efficiency of the Files.walkFileTree(), let's find the longest path that doesn't need globbing.
64 * We look for the first glob character * { ? and then look for the last File.separator before that.
65 * Then we can reset the path to look at and shorten the globbing pattern.
66 * Relative paths can be used in pattern, which work from the pwd (though these are converted into
67 * full paths in the match).
69 int firstGlobChar = -1;
70 boolean foundGlobChar = false;
71 for (char c : new char[] { '*', '{', '?' })
73 if (pattern.indexOf(c) > -1
74 && (pattern.indexOf(c) < firstGlobChar || !foundGlobChar))
76 firstGlobChar = pattern.indexOf(c);
80 int lastFS = pattern.lastIndexOf(File.separatorChar, firstGlobChar);
83 String pS = pattern.substring(0, lastFS + 1);
84 String rest = pattern.substring(lastFS + 1);
89 Path parentDir = Paths.get(pS);
90 if (parentDir.toFile().exists())
94 String glob = "glob:" + parentDir.toString() + File.separator
96 PathMatcher pm = FileSystems.getDefault().getPathMatcher(glob);
97 int maxDepth = rest.contains("**") ? 1028
99 .filter(ch -> ch == File.separatorChar).count())
102 Files.walkFileTree(parentDir,
103 EnumSet.of(FileVisitOption.FOLLOW_LINKS), maxDepth,
104 new SimpleFileVisitor<Path>()
107 public FileVisitResult visitFile(Path path,
108 BasicFileAttributes attrs) throws IOException
110 if (pm.matches(path))
112 files.add(path.toFile());
114 return FileVisitResult.CONTINUE;
118 public FileVisitResult visitFileFailed(Path file,
119 IOException exc) throws IOException
121 return FileVisitResult.CONTINUE;
124 } catch (IOException e)
133 File f = new File(pattern);
134 if (allowSingleFilenameThatDoesNotExist || f.exists())
139 Collections.sort(files);
144 public static List<String> getFilenamesFromGlob(String pattern)
146 // convert list of Files to list of File.getPath() Strings
147 return getFilesFromGlob(pattern).stream().map(f -> f.getPath())
148 .collect(Collectors.toList());
151 public static String substituteHomeDir(String path)
153 return path.startsWith("~" + File.separator)
154 ? System.getProperty("user.home") + path.substring(1)
159 * This method returns the basename of File file
161 public static String getBasename(File file)
163 return getBasenameOrExtension(file, false);
167 * This method returns the extension of File file.
169 public static String getExtension(File file)
171 return getBasenameOrExtension(file, true);
174 public static String getBasenameOrExtension(File file, boolean extension)
180 String filename = file.getName();
181 int lastDot = filename.lastIndexOf('.');
182 if (lastDot > 0) // don't truncate if starts with '.'
184 value = extension ? filename.substring(lastDot + 1)
185 : filename.substring(0, lastDot);
189 value = extension ? "" : filename;
195 * This method returns the dirname of the first --append or --open value.
196 * Used primarily for substitutions in output filenames.
198 public static String getDirname(File file)
203 String dirname = null;
204 File p = file.getParentFile();
209 File d = new File(substituteHomeDir(p.getPath()));
210 dirname = d.getPath();
214 public static String convertWildcardsToPath(String value, String wildcard,
215 String dirname, String basename)
221 StringBuilder path = new StringBuilder();
222 int lastFileSeparatorIndex = value.lastIndexOf(File.separatorChar);
223 int wildcardBeforeIndex = value.indexOf(wildcard);
224 if (lastFileSeparatorIndex > wildcard.length() - 1
225 && wildcardBeforeIndex < lastFileSeparatorIndex)
227 path.append(value.substring(0, wildcardBeforeIndex));
228 path.append(dirname);
229 path.append(value.substring(wildcardBeforeIndex + wildcard.length(),
230 lastFileSeparatorIndex + 1));
234 path.append(value.substring(0, lastFileSeparatorIndex + 1));
236 int wildcardAfterIndex = value.indexOf(wildcard,
237 lastFileSeparatorIndex);
238 if (wildcardAfterIndex > lastFileSeparatorIndex)
240 path.append(value.substring(lastFileSeparatorIndex + 1,
241 wildcardAfterIndex));
242 path.append(basename);
243 path.append(value.substring(wildcardAfterIndex + wildcard.length()));
247 path.append(value.substring(lastFileSeparatorIndex + 1));
249 return path.toString();
252 public static File getParentDir(File file)
258 File parentDir = file.getAbsoluteFile().getParentFile();
262 public static boolean checkParentDir(File file, boolean mkdirs)
268 File parentDir = getParentDir(file);
269 if (parentDir.exists())
271 // already exists, nothing to do so nothing to worry about!
280 Path path = file.toPath();
281 for (int i = 0; i < path.getNameCount(); i++)
283 Path p = path.getName(i);
284 if ("..".equals(p.toString()))
286 Console.warn("Cautiously not running mkdirs on " + file.toString()
287 + " because the path to be made contains '..'");
292 return parentDir.mkdirs();