Clover icon

Coverage Report

  1. Project Clover database Mon Sep 2 2024 17:57:51 BST
  2. Package jalview.util

File FileUtils.java

 

Coverage histogram

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

Code metrics

60
110
16
1
364
274
53
0.48
6.88
16
3.31

Classes

Class Line # Actions
FileUtils 44 110 53
0.7849462678.5%
 

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 PathMatcher pm = FileSystems.getDefault().getPathMatcher(glob);
99  55 int maxDepth = rest.contains("**") ? 1028
100    : (int) (rest.chars()
101    .filter(ch -> ch == File.separatorChar).count())
102    + 1;
103   
104  55 Files.walkFileTree(parentDir,
105    EnumSet.of(FileVisitOption.FOLLOW_LINKS), maxDepth,
106    new SimpleFileVisitor<Path>()
107    {
 
108  6411 toggle @Override
109    public FileVisitResult visitFile(Path path,
110    BasicFileAttributes attrs) throws IOException
111    {
112  6411 if (pm.matches(path))
113    {
114  3153 files.add(path.toFile());
115    }
116  6411 return FileVisitResult.CONTINUE;
117    }
118   
 
119  0 toggle @Override
120    public FileVisitResult visitFileFailed(Path file,
121    IOException exc) throws IOException
122    {
123  0 return FileVisitResult.CONTINUE;
124    }
125    });
126    } catch (IOException e)
127    {
128  0 e.printStackTrace();
129    }
130    }
131    }
132    else
133    {
134    // no wildcards
135  109 File f = new File(pattern);
136  109 if (allowSingleFilenameThatDoesNotExist || f.exists())
137    {
138  109 files.add(f);
139    }
140    }
141  164 Collections.sort(files);
142   
143  164 return files;
144    }
145   
 
146  139 toggle public static List<String> getFilenamesFromGlob(String pattern)
147    {
148    // convert list of Files to list of File.getPath() Strings
149  139 return getFilesFromGlob(pattern).stream().map(f -> f.getPath())
150    .collect(Collectors.toList());
151    }
152   
 
153  355 toggle public static String substituteHomeDir(String path)
154    {
155  355 return path.startsWith("~" + File.separator)
156    ? System.getProperty("user.home") + path.substring(1)
157    : path;
158    }
159   
160    /*
161    * This method returns the basename of File file
162    */
 
163  78 toggle public static String getBasename(File file)
164    {
165  78 return getBasenameOrExtension(file, false);
166    }
167   
168    /*
169    * This method returns the extension of File file.
170    */
 
171  10 toggle public static String getExtension(File file)
172    {
173  10 return getBasenameOrExtension(file, true);
174    }
175   
 
176  88 toggle public static String getBasenameOrExtension(File file, boolean extension)
177    {
178  88 if (file == null)
179  0 return null;
180   
181  88 String value = null;
182  88 String filename = file.getName();
183  88 int lastDot = filename.lastIndexOf('.');
184  88 if (lastDot > 0) // don't truncate if starts with '.'
185    {
186  87 value = extension ? filename.substring(lastDot + 1)
187    : filename.substring(0, lastDot);
188    }
189    else
190    {
191  1 value = extension ? "" : filename;
192    }
193  88 return value;
194    }
195   
196    /*
197    * This method returns the dirname of the first --append or --open value.
198    * Used primarily for substitutions in output filenames.
199    */
 
200  104 toggle public static String getDirname(File file)
201    {
202  104 if (file == null)
203  0 return null;
204   
205  104 String dirname = null;
206  104 File p = file.getParentFile();
207  104 if (p == null)
208    {
209  0 p = new File(".");
210    }
211  104 File d = new File(substituteHomeDir(p.getPath()));
212  104 dirname = d.getPath();
213  104 return dirname;
214    }
215   
 
216  19 toggle public static String convertWildcardsToPath(String value, String wildcard,
217    String dirname, String basename)
218    {
219  19 if (value == null)
220    {
221  0 return null;
222    }
223  19 StringBuilder path = new StringBuilder();
224  19 int lastFileSeparatorIndex = value.lastIndexOf(File.separatorChar);
225  19 int wildcardBeforeIndex = value.indexOf(wildcard);
226  19 if (lastFileSeparatorIndex > wildcard.length() - 1
227    && wildcardBeforeIndex < lastFileSeparatorIndex)
228    {
229  12 path.append(value.substring(0, wildcardBeforeIndex));
230  12 path.append(dirname);
231  12 path.append(value.substring(wildcardBeforeIndex + wildcard.length(),
232    lastFileSeparatorIndex + 1));
233    }
234    else
235    {
236  7 path.append(value.substring(0, lastFileSeparatorIndex + 1));
237    }
238  19 int wildcardAfterIndex = value.indexOf(wildcard,
239    lastFileSeparatorIndex);
240  19 if (wildcardAfterIndex > lastFileSeparatorIndex)
241    {
242  14 path.append(value.substring(lastFileSeparatorIndex + 1,
243    wildcardAfterIndex));
244  14 path.append(basename);
245  14 path.append(value.substring(wildcardAfterIndex + wildcard.length()));
246    }
247    else
248    {
249  5 path.append(value.substring(lastFileSeparatorIndex + 1));
250    }
251  19 return path.toString();
252    }
253   
 
254  114 toggle public static File getParentDir(File file)
255    {
256  114 if (file == null)
257    {
258  0 return null;
259    }
260  114 File parentDir = file.getAbsoluteFile().getParentFile();
261  114 return parentDir;
262    }
263   
 
264  114 toggle public static boolean checkParentDir(File file, boolean mkdirs)
265    {
266  114 if (file == null)
267    {
268  0 return false;
269    }
270  114 File parentDir = getParentDir(file);
271  114 if (parentDir.exists())
272    {
273    // already exists, nothing to do so nothing to worry about!
274  114 return true;
275    }
276   
277  0 if (!mkdirs)
278    {
279  0 return false;
280    }
281   
282  0 Path path = file.toPath();
283  0 for (int i = 0; i < path.getNameCount(); i++)
284    {
285  0 Path p = path.getName(i);
286  0 if ("..".equals(p.toString()))
287    {
288  0 Console.warn("Cautiously not running mkdirs on " + file.toString()
289    + " because the path to be made contains '..'");
290  0 return false;
291    }
292    }
293   
294  0 return parentDir.mkdirs();
295    }
296   
297    /**
298    * get a guessed file extension from a String only
299    *
300    * @param String
301    * filename
302    * @return String extension
303    */
 
304  15 toggle public static String getExtension(String filename)
305    {
306  15 return getBaseOrExtension(filename, true);
307    }
308   
309    /**
310    * getBase returns everything in a path/URI up to (and including) an extension
311    * dot. Note this is not the same as getBasename() since getBasename() only
312    * gives the filename base, not the path too. If no extension dot is found
313    * (i.e. a dot in character position 2 or more of the filename (after the last
314    * slash) then the whole path is considered the base.
315    *
316    * @param filename
317    * @return String base
318    */
 
319  15 toggle public static String getBase(String filename)
320    {
321  15 return getBaseOrExtension(filename, false);
322    }
323   
 
324  30 toggle public static String getBaseOrExtension(String filename0,
325    boolean extension)
326    {
327  30 if (filename0 == null)
328    {
329  0 return null;
330    }
331  30 String filename = filename0;
332  30 boolean isUrl = false;
333  30 if (HttpUtils.startsWithHttpOrHttps(filename))
334    {
335  10 try
336    {
337  10 URL url = new URL(filename);
338  10 filename = url.getPath();
339  10 isUrl = true;
340    } catch (MalformedURLException e)
341    {
342    // continue to treat as a filename
343    }
344    }
345  30 int dot = filename.lastIndexOf('.');
346  30 int slash = filename.lastIndexOf('/');
347  30 if (!File.separator.equals("/") && !isUrl)
348    {
349  0 slash = filename.lastIndexOf(File.separator);
350    }
351    // only the dot of the filename (not dots in path) and not if it's a .hidden
352    // file
353  30 boolean hasExtension = dot > slash + 1;
354  30 if (extension)
355    {
356  15 return hasExtension ? filename.substring(dot + 1) : null;
357    }
358    else
359    {
360  15 dot = filename0.lastIndexOf('.');
361  15 return hasExtension ? filename0.substring(0, dot + 1) : filename0;
362    }
363    }
364    }