Clover icon

Coverage Report

  1. Project Clover database Wed Nov 6 2024 00:56:24 GMT
  2. Package jalview.util

File FileUtils.java

 

Coverage histogram

../../img/srcFileCovDistChart8.png
20% of files have more coverage

Code metrics

62
112
16
1
371
278
54
0.48
7
16
3.38

Classes

Class Line # Actions
FileUtils 44 112 54
0.7789473577.9%
 

Contributing tests

This file is covered by 137 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
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.
11    *
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.
16    *
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.
20    */
21    package jalview.util;
22   
23    import java.io.File;
24    import java.io.IOException;
25    import java.net.MalformedURLException;
26    import java.net.URL;
27    import java.nio.file.FileSystems;
28    import java.nio.file.FileVisitOption;
29    import java.nio.file.FileVisitResult;
30    import java.nio.file.Files;
31    import java.nio.file.Path;
32    import java.nio.file.PathMatcher;
33    import java.nio.file.Paths;
34    import java.nio.file.SimpleFileVisitor;
35    import java.nio.file.attribute.BasicFileAttributes;
36    import java.util.ArrayList;
37    import java.util.Collections;
38    import java.util.EnumSet;
39    import java.util.List;
40    import java.util.stream.Collectors;
41   
42    import jalview.bin.Console;
43   
 
44    public class FileUtils
45    {
46    /*
47    * Given string glob pattern (see
48    * https://docs.oracle.com/javase/7/docs/api/java/nio/file/FileSystem.html#getPathMatcher(java.lang.String)
49    * ) return a List of Files that match the pattern.
50    * Note this is a java style glob, not necessarily a bash-style glob, though there are sufficient similarities.
51    */
 
52  164 toggle public static List<File> getFilesFromGlob(String pattern)
53    {
54  164 return getFilesFromGlob(pattern, true);
55    }
56   
 
57  164 toggle public static List<File> getFilesFromGlob(String pattern,
58    boolean allowSingleFilenameThatDoesNotExist)
59    {
60  164 pattern = substituteHomeDir(pattern);
61  164 String relativePattern = pattern.startsWith(File.separator) ? null
62    : pattern;
63  164 List<File> files = new ArrayList<>();
64    /*
65    * For efficiency of the Files.walkFileTree(), let's find the longest path that doesn't need globbing.
66    * We look for the first glob character * { ? and then look for the last File.separator before that.
67    * Then we can reset the path to look at and shorten the globbing pattern.
68    * Relative paths can be used in pattern, which work from the pwd (though these are converted into
69    * full paths in the match).
70    */
71  164 int firstGlobChar = -1;
72  164 boolean foundGlobChar = false;
73  164 for (char c : new char[] { '*', '{', '?' })
74    {
75  492 if (pattern.indexOf(c) > -1
76    && (pattern.indexOf(c) < firstGlobChar || !foundGlobChar))
77    {
78  55 firstGlobChar = pattern.indexOf(c);
79  55 foundGlobChar = true;
80    }
81    }
82  164 int lastFS = pattern.lastIndexOf(File.separatorChar, firstGlobChar);
83  164 if (foundGlobChar)
84    {
85  55 String pS = pattern.substring(0, lastFS + 1);
86  55 String rest = pattern.substring(lastFS + 1);
87  55 if ("".equals(pS))
88    {
89  0 pS = ".";
90    }
91  55 Path parentDir = Paths.get(pS);
92  55 if (parentDir.toFile().exists())
93    {
94  55 try
95    {
96  55 String glob = "glob:" + parentDir.toString() + File.separator
97    + rest;
98  55 if (Platform.isWin())
99    {
100    // escape "\\" on Windows
101    // This ultimately replaces "\\" == '\' with "\\\\" = '\\' to escape
102    // backslashes
103  0 glob = glob.replaceAll("\\\\", "\\\\\\\\");
104    }
105  55 PathMatcher pm = FileSystems.getDefault().getPathMatcher(glob);
106  55 int maxDepth = rest.contains("**") ? 1028
107    : (int) (rest.chars()
108    .filter(ch -> ch == File.separatorChar).count())
109    + 1;
110   
111  55 Files.walkFileTree(parentDir,
112    EnumSet.of(FileVisitOption.FOLLOW_LINKS), maxDepth,
113    new SimpleFileVisitor<Path>()
114    {
 
115  6421 toggle @Override
116    public FileVisitResult visitFile(Path path,
117    BasicFileAttributes attrs) throws IOException
118    {
119  6421 if (pm.matches(path))
120    {
121  3157 files.add(path.toFile());
122    }
123  6421 return FileVisitResult.CONTINUE;
124    }
125   
 
126  0 toggle @Override
127    public FileVisitResult visitFileFailed(Path file,
128    IOException exc) throws IOException
129    {
130  0 return FileVisitResult.CONTINUE;
131    }
132    });
133    } catch (IOException e)
134    {
135  0 e.printStackTrace();
136    }
137    }
138    }
139    else
140    {
141    // no wildcards
142  109 File f = new File(pattern);
143  109 if (allowSingleFilenameThatDoesNotExist || f.exists())
144    {
145  109 files.add(f);
146    }
147    }
148  164 Collections.sort(files);
149   
150  164 return files;
151    }
152   
 
153  139 toggle public static List<String> getFilenamesFromGlob(String pattern)
154    {
155    // convert list of Files to list of File.getPath() Strings
156  139 return getFilesFromGlob(pattern).stream().map(f -> f.getPath())
157    .collect(Collectors.toList());
158    }
159   
 
160  355 toggle public static String substituteHomeDir(String path)
161    {
162  355 return path.startsWith("~" + File.separator)
163    ? System.getProperty("user.home") + path.substring(1)
164    : path;
165    }
166   
167    /*
168    * This method returns the basename of File file
169    */
 
170  78 toggle public static String getBasename(File file)
171    {
172  78 return getBasenameOrExtension(file, false);
173    }
174   
175    /*
176    * This method returns the extension of File file.
177    */
 
178  10 toggle public static String getExtension(File file)
179    {
180  10 return getBasenameOrExtension(file, true);
181    }
182   
 
183  88 toggle public static String getBasenameOrExtension(File file, boolean extension)
184    {
185  88 if (file == null)
186  0 return null;
187   
188  88 String value = null;
189  88 String filename = file.getName();
190  88 int lastDot = filename.lastIndexOf('.');
191  88 if (lastDot > 0) // don't truncate if starts with '.'
192    {
193  87 value = extension ? filename.substring(lastDot + 1)
194    : filename.substring(0, lastDot);
195    }
196    else
197    {
198  1 value = extension ? "" : filename;
199    }
200  88 return value;
201    }
202   
203    /*
204    * This method returns the dirname of the first --append or --open value.
205    * Used primarily for substitutions in output filenames.
206    */
 
207  104 toggle public static String getDirname(File file)
208    {
209  104 if (file == null)
210  0 return null;
211   
212  104 String dirname = null;
213  104 File p = file.getParentFile();
214  104 if (p == null)
215    {
216  0 p = new File(".");
217    }
218  104 File d = new File(substituteHomeDir(p.getPath()));
219  104 dirname = d.getPath();
220  104 return dirname;
221    }
222   
 
223  19 toggle public static String convertWildcardsToPath(String value, String wildcard,
224    String dirname, String basename)
225    {
226  19 if (value == null)
227    {
228  0 return null;
229    }
230  19 StringBuilder path = new StringBuilder();
231  19 int lastFileSeparatorIndex = value.lastIndexOf(File.separatorChar);
232  19 int wildcardBeforeIndex = value.indexOf(wildcard);
233  19 if (lastFileSeparatorIndex > wildcard.length() - 1
234    && wildcardBeforeIndex < lastFileSeparatorIndex)
235    {
236  12 path.append(value.substring(0, wildcardBeforeIndex));
237  12 path.append(dirname);
238  12 path.append(value.substring(wildcardBeforeIndex + wildcard.length(),
239    lastFileSeparatorIndex + 1));
240    }
241    else
242    {
243  7 path.append(value.substring(0, lastFileSeparatorIndex + 1));
244    }
245  19 int wildcardAfterIndex = value.indexOf(wildcard,
246    lastFileSeparatorIndex);
247  19 if (wildcardAfterIndex > lastFileSeparatorIndex)
248    {
249  14 path.append(value.substring(lastFileSeparatorIndex + 1,
250    wildcardAfterIndex));
251  14 path.append(basename);
252  14 path.append(value.substring(wildcardAfterIndex + wildcard.length()));
253    }
254    else
255    {
256  5 path.append(value.substring(lastFileSeparatorIndex + 1));
257    }
258  19 return path.toString();
259    }
260   
 
261  114 toggle public static File getParentDir(File file)
262    {
263  114 if (file == null)
264    {
265  0 return null;
266    }
267  114 File parentDir = file.getAbsoluteFile().getParentFile();
268  114 return parentDir;
269    }
270   
 
271  114 toggle public static boolean checkParentDir(File file, boolean mkdirs)
272    {
273  114 if (file == null)
274    {
275  0 return false;
276    }
277  114 File parentDir = getParentDir(file);
278  114 if (parentDir.exists())
279    {
280    // already exists, nothing to do so nothing to worry about!
281  114 return true;
282    }
283   
284  0 if (!mkdirs)
285    {
286  0 return false;
287    }
288   
289  0 Path path = file.toPath();
290  0 for (int i = 0; i < path.getNameCount(); i++)
291    {
292  0 Path p = path.getName(i);
293  0 if ("..".equals(p.toString()))
294    {
295  0 Console.warn("Cautiously not running mkdirs on " + file.toString()
296    + " because the path to be made contains '..'");
297  0 return false;
298    }
299    }
300   
301  0 return parentDir.mkdirs();
302    }
303   
304    /**
305    * get a guessed file extension from a String only
306    *
307    * @param String
308    * filename
309    * @return String extension
310    */
 
311  15 toggle public static String getExtension(String filename)
312    {
313  15 return getBaseOrExtension(filename, true);
314    }
315   
316    /**
317    * getBase returns everything in a path/URI up to (and including) an extension
318    * dot. Note this is not the same as getBasename() since getBasename() only
319    * gives the filename base, not the path too. If no extension dot is found
320    * (i.e. a dot in character position 2 or more of the filename (after the last
321    * slash) then the whole path is considered the base.
322    *
323    * @param filename
324    * @return String base
325    */
 
326  15 toggle public static String getBase(String filename)
327    {
328  15 return getBaseOrExtension(filename, false);
329    }
330   
 
331  30 toggle public static String getBaseOrExtension(String filename0,
332    boolean extension)
333    {
334  30 if (filename0 == null)
335    {
336  0 return null;
337    }
338  30 String filename = filename0;
339  30 boolean isUrl = false;
340  30 if (HttpUtils.startsWithHttpOrHttps(filename))
341    {
342  10 try
343    {
344  10 URL url = new URL(filename);
345  10 filename = url.getPath();
346  10 isUrl = true;
347    } catch (MalformedURLException e)
348    {
349    // continue to treat as a filename
350    }
351    }
352  30 int dot = filename.lastIndexOf('.');
353  30 int slash = filename.lastIndexOf('/');
354  30 if (!File.separator.equals("/") && !isUrl)
355    {
356  0 slash = filename.lastIndexOf(File.separator);
357    }
358    // only the dot of the filename (not dots in path) and not if it's a .hidden
359    // file
360  30 boolean hasExtension = dot > slash + 1;
361  30 if (extension)
362    {
363  15 return hasExtension ? filename.substring(dot + 1) : null;
364    }
365    else
366    {
367  15 dot = filename0.lastIndexOf('.');
368  15 return hasExtension ? filename0.substring(0, dot + 1) : filename0;
369    }
370    }
371    }