1 /* 2 * This file is part of ELKI: 3 * Environment for Developing KDD-Applications Supported by Index-Structures 4 * 5 * Copyright (C) 2018 6 * ELKI Development Team 7 * 8 * This program is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Affero General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Affero General Public License for more details. 17 * 18 * You should have received a copy of the GNU Affero General Public License 19 * along with this program. If not, see <http://www.gnu.org/licenses/>. 20 */ 21 package de.lmu.ifi.dbs.elki.utilities.io; 22 23 import java.io.File; 24 import java.io.FileInputStream; 25 import java.io.FileNotFoundException; 26 import java.io.IOException; 27 import java.io.InputStream; 28 import java.io.PushbackInputStream; 29 import java.net.URL; 30 import java.net.URLConnection; 31 import java.util.zip.GZIPInputStream; 32 33 /** 34 * Various static helper methods to deal with files and file names. 35 * 36 * @author Erich Schubert 37 * @since 0.2 38 */ 39 public final class FileUtil { 40 /** 41 * Fake Constructor. Use static methods. 42 * 43 */ FileUtil()44 private FileUtil() { 45 // Do not instantiate. 46 } 47 48 /** 49 * Returns the lower case extension of the selected file. 50 * 51 * If no file is selected, <code>null</code> is returned. 52 * 53 * @param file File object 54 * @return Returns the extension of the selected file in lower case or 55 * <code>null</code> 56 */ getFilenameExtension(File file)57 public static String getFilenameExtension(File file) { 58 return getFilenameExtension(file.getName()); 59 } 60 61 /** 62 * Returns the lower case extension of the selected file. 63 * 64 * If no file is selected, <code>null</code> is returned. 65 * 66 * @param name File name 67 * @return Returns the extension of the selected file in lower case or 68 * <code>null</code> 69 */ getFilenameExtension(String name)70 public static String getFilenameExtension(String name) { 71 if(name == null) { 72 return null; 73 } 74 int index = name.lastIndexOf('.'); 75 return index < 0 ? null : name.substring(index + 1).toLowerCase(); 76 } 77 78 /** 79 * Try to open a file, first trying the file system, then falling back to the 80 * classpath. 81 * 82 * @param filename File name in system notation 83 * @return Input stream 84 * @throws FileNotFoundException When no file was found. 85 */ openSystemFile(String filename)86 public static InputStream openSystemFile(String filename) throws FileNotFoundException { 87 try { 88 return new FileInputStream(filename); 89 } 90 catch(FileNotFoundException e) { 91 // try with classloader 92 String resname = File.separatorChar != '/' ? filename.replace(File.separatorChar, '/') : filename; 93 ClassLoader cl = FileUtil.class.getClassLoader(); 94 InputStream result = cl.getResourceAsStream(resname); 95 if(result != null) { 96 return result; 97 } 98 // Sometimes, URLClassLoader does not work right. Try harder: 99 URL u = cl.getResource(resname); 100 if(u == null) { 101 throw e; 102 } 103 try { 104 URLConnection conn = u.openConnection(); 105 conn.setUseCaches(false); 106 if((result = conn.getInputStream()) != null) { 107 return result; 108 } 109 } 110 catch(IOException x) { 111 throw e; // Throw original error instead. 112 } 113 throw e; 114 } 115 } 116 117 /** 118 * Try to open a stream as gzip, if it starts with the gzip magic. 119 * 120 * @param in original input stream 121 * @return old input stream or a {@link GZIPInputStream} if appropriate. 122 * @throws IOException on IO error 123 */ tryGzipInput(InputStream in)124 public static InputStream tryGzipInput(InputStream in) throws IOException { 125 // try autodetecting gzip compression. 126 if(!in.markSupported()) { 127 PushbackInputStream pb = new PushbackInputStream(in, 16); 128 // read a magic from the file header, and push it back 129 byte[] magic = { 0, 0 }; 130 int r = pb.read(magic); 131 pb.unread(magic, 0, r); 132 return (magic[0] == 31 && magic[1] == -117) ? new GZIPInputStream(pb) : pb; 133 } 134 // Mark is supported. 135 in.mark(16); 136 boolean isgzip = ((in.read() << 8) | in.read()) == GZIPInputStream.GZIP_MAGIC; 137 in.reset(); // Rewind 138 return isgzip ? new GZIPInputStream(in) : in; 139 } 140 141 /** 142 * Try to locate an file in the filesystem, given a partial name and a prefix. 143 * 144 * @param name file name 145 * @param basedir extra base directory to try 146 * @return file, if the file could be found. {@code null} otherwise 147 */ locateFile(String name, String basedir)148 public static File locateFile(String name, String basedir) { 149 // Try exact match first. 150 File f = new File(name); 151 if(f.exists()) { 152 return f; 153 } 154 // Try with base directory 155 if(basedir != null) { 156 if((f = new File(basedir, name)).exists()) { 157 return f; 158 } 159 } 160 // try stripping whitespace 161 String name2; 162 if(!name.equals(name2 = name.trim())) { 163 if((f = locateFile(name2, basedir)) != null) { 164 return f; 165 } 166 } 167 // try substituting path separators 168 if(!name.equals(name2 = name.replace('/', File.separatorChar))) { 169 if((f = locateFile(name2, basedir)) != null) { 170 return f; 171 } 172 } 173 if(!name.equals(name2 = name.replace('\\', File.separatorChar))) { 174 if((f = locateFile(name2, basedir)) != null) { 175 return f; 176 } 177 } 178 // try stripping extra characters, such as quotes. 179 if(name.length() > 2 && name.charAt(0) == '"' && name.charAt(name.length() - 1) == '"') { 180 if((f = locateFile(name.substring(1, name.length() - 1), basedir)) != null) { 181 return f; 182 } 183 } 184 return null; 185 } 186 187 /** 188 * Load an input stream (e.g., a Java resource) into a String buffer. The 189 * stream is closed afterwards. 190 * 191 * @param is Input stream 192 * @return String with file/resource contents. 193 * @throws IOException on IO errors 194 */ slurp(InputStream is)195 public static String slurp(InputStream is) throws IOException { 196 StringBuilder buf = new StringBuilder(); 197 final byte[] b = new byte[4096]; 198 for(int n; (n = is.read(b)) != -1;) { 199 buf.append(new String(b, 0, n)); 200 } 201 is.close(); 202 return buf.toString(); 203 } 204 } 205