/* * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ package jalview.util; import java.io.File; import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.FileVisitOption; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.stream.Collectors; import jalview.bin.Console; public class FileUtils { /* * Given string glob pattern (see * https://docs.oracle.com/javase/7/docs/api/java/nio/file/FileSystem.html#getPathMatcher(java.lang.String) * ) return a List of Files that match the pattern. * Note this is a java style glob, not necessarily a bash-style glob, though there are sufficient similarities. */ public static List getFilesFromGlob(String pattern) { return getFilesFromGlob(pattern, true); } public static List getFilesFromGlob(String pattern, boolean allowSingleFilenameThatDoesNotExist) { pattern = substituteHomeDir(pattern); String relativePattern = pattern.startsWith(File.separator) ? null : pattern; List files = new ArrayList<>(); /* * For efficiency of the Files.walkFileTree(), let's find the longest path that doesn't need globbing. * We look for the first glob character * { ? and then look for the last File.separator before that. * Then we can reset the path to look at and shorten the globbing pattern. * Relative paths can be used in pattern, which work from the pwd (though these are converted into * full paths in the match). */ int firstGlobChar = -1; boolean foundGlobChar = false; for (char c : new char[] { '*', '{', '?' }) { if (pattern.indexOf(c) > -1 && (pattern.indexOf(c) < firstGlobChar || !foundGlobChar)) { firstGlobChar = pattern.indexOf(c); foundGlobChar = true; } } int lastFS = pattern.lastIndexOf(File.separatorChar, firstGlobChar); if (foundGlobChar) { String pS = pattern.substring(0, lastFS + 1); String rest = pattern.substring(lastFS + 1); if ("".equals(pS)) { pS = "."; } Path parentDir = Paths.get(pS); if (parentDir.toFile().exists()) { try { String glob = "glob:" + parentDir.toString() + File.separator + rest; PathMatcher pm = FileSystems.getDefault().getPathMatcher(glob); int maxDepth = rest.contains("**") ? 1028 : (int) (rest.chars() .filter(ch -> ch == File.separatorChar).count()) + 1; Files.walkFileTree(parentDir, EnumSet.of(FileVisitOption.FOLLOW_LINKS), maxDepth, new SimpleFileVisitor() { @Override public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { if (pm.matches(path)) { files.add(path.toFile()); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { return FileVisitResult.CONTINUE; } }); } catch (IOException e) { e.printStackTrace(); } } } else { // no wildcards File f = new File(pattern); if (allowSingleFilenameThatDoesNotExist || f.exists()) { files.add(f); } } Collections.sort(files); return files; } public static List getFilenamesFromGlob(String pattern) { // convert list of Files to list of File.getPath() Strings return getFilesFromGlob(pattern).stream().map(f -> f.getPath()) .collect(Collectors.toList()); } public static String substituteHomeDir(String path) { return path.startsWith("~" + File.separator) ? System.getProperty("user.home") + path.substring(1) : path; } /* * This method returns the basename of File file */ public static String getBasename(File file) { return getBasenameOrExtension(file, false); } /* * This method returns the extension of File file. */ public static String getExtension(File file) { return getBasenameOrExtension(file, true); } public static String getBasenameOrExtension(File file, boolean extension) { if (file == null) return null; String value = null; String filename = file.getName(); int lastDot = filename.lastIndexOf('.'); if (lastDot > 0) // don't truncate if starts with '.' { value = extension ? filename.substring(lastDot + 1) : filename.substring(0, lastDot); } else { value = extension ? "" : filename; } return value; } /* * This method returns the dirname of the first --append or --open value. * Used primarily for substitutions in output filenames. */ public static String getDirname(File file) { if (file == null) return null; String dirname = null; File p = file.getParentFile(); if (p == null) { p = new File("."); } File d = new File(substituteHomeDir(p.getPath())); dirname = d.getPath(); return dirname; } public static String convertWildcardsToPath(String value, String wildcard, String dirname, String basename) { if (value == null) { return null; } StringBuilder path = new StringBuilder(); int lastFileSeparatorIndex = value.lastIndexOf(File.separatorChar); int wildcardBeforeIndex = value.indexOf(wildcard); if (lastFileSeparatorIndex > wildcard.length() - 1 && wildcardBeforeIndex < lastFileSeparatorIndex) { path.append(value.substring(0, wildcardBeforeIndex)); path.append(dirname); path.append(value.substring(wildcardBeforeIndex + wildcard.length(), lastFileSeparatorIndex + 1)); } else { path.append(value.substring(0, lastFileSeparatorIndex + 1)); } int wildcardAfterIndex = value.indexOf(wildcard, lastFileSeparatorIndex); if (wildcardAfterIndex > lastFileSeparatorIndex) { path.append(value.substring(lastFileSeparatorIndex + 1, wildcardAfterIndex)); path.append(basename); path.append(value.substring(wildcardAfterIndex + wildcard.length())); } else { path.append(value.substring(lastFileSeparatorIndex + 1)); } return path.toString(); } public static File getParentDir(File file) { if (file == null) { return null; } File parentDir = file.getAbsoluteFile().getParentFile(); return parentDir; } public static boolean checkParentDir(File file, boolean mkdirs) { if (file == null) { return false; } File parentDir = getParentDir(file); if (parentDir.exists()) { // already exists, nothing to do so nothing to worry about! return true; } if (!mkdirs) { return false; } Path path = file.toPath(); for (int i = 0; i < path.getNameCount(); i++) { Path p = path.getName(i); if ("..".equals(p.toString())) { Console.warn("Cautiously not running mkdirs on " + file.toString() + " because the path to be made contains '..'"); return false; } } return parentDir.mkdirs(); } }