X-Git-Url: http://source.jalview.org/gitweb/?p=jalview.git;a=blobdiff_plain;f=src%2Fjalview%2Futil%2FFileUtils.java;fp=src%2Fjalview%2Futil%2FFileUtils.java;h=e7d274c117fcb01c12901dedcfc728889c568d5d;hp=0000000000000000000000000000000000000000;hb=c1e71094304dcd2b975c485416ec5e25cca30815;hpb=bd990168d0b3c7772c961b56144c3dee94a09054 diff --git a/src/jalview/util/FileUtils.java b/src/jalview/util/FileUtils.java new file mode 100644 index 0000000..e7d274c --- /dev/null +++ b/src/jalview/util/FileUtils.java @@ -0,0 +1,294 @@ +/* + * 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(); + } +}