1 /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved. 2 * 3 * This program and the accompanying materials are made available under 4 * the terms of the Common Public License v1.0 which accompanies this distribution, 5 * and is available at http://www.eclipse.org/legal/cpl-v10.html 6 * 7 * $Id: Files.java,v 1.1.1.1.2.1 2004/07/09 01:28:37 vlad_r Exp $ 8 */ 9 package com.vladium.util; 10 11 import java.io.BufferedReader; 12 import java.io.File; 13 import java.io.FileReader; 14 import java.io.IOException; 15 import java.util.ArrayList; 16 import java.util.HashSet; 17 import java.util.LinkedList; 18 import java.util.List; 19 import java.util.Set; 20 import java.util.StringTokenizer; 21 22 // ---------------------------------------------------------------------------- 23 /** 24 * @author Vlad Roubtsov, (C) 2003 25 */ 26 public 27 abstract class Files 28 { 29 // public: ................................................................ 30 31 /** 32 * No duplicate elimination. 33 * 34 * @param atfile 35 */ 36 public static String [] readFileList (final File atfile) 37 throws IOException 38 { 39 if (atfile == null) throw new IllegalArgumentException ("null input: atfile"); 40 41 List _result = null; 42 43 BufferedReader in = null; 44 try 45 { 46 in = new BufferedReader (new FileReader (atfile), 8 * 1024); // uses default encoding 47 _result = new LinkedList (); 48 49 for (String line; (line = in.readLine ()) != null; ) 50 { 51 line = line.trim (); 52 if ((line.length () == 0) || (line.charAt (0) == '#')) continue; 53 54 _result.add (line); 55 } 56 } 57 finally 58 { 59 if (in != null) try { in.close (); } catch (Exception ignore) {} 60 } 61 62 if ((_result == null) || _result.isEmpty ()) 63 return IConstants.EMPTY_STRING_ARRAY; 64 else 65 { 66 final String [] result = new String [_result.size ()]; 67 _result.toArray (result); 68 69 return result; 70 } 71 } 72 73 /** 74 * Converts an array of path segments to an array of Files. The order 75 * of files follows the original order of path segments, except "duplicate" 76 * entries are removed. The definition of duplicates depends on 'canonical': 77 * <ul> 78 * <li> if 'canonical'=true, the pathnames are canonicalized via {@link #canonicalizePathname} 79 * before they are compared for equality 80 * <li> if 'canonical'=false, the pathnames are compared as case-sensitive strings 81 * </ul> 82 * 83 * Note that duplicate removal in classpaths affects ClassLoader.getResources(). 84 * The first mode above makes the most sense, however the last one is what 85 * Sun's java.net.URLClassLoader appears to do. Hence the last mode might be 86 * necessary for reproducing its behavior in Sun-compatible JVMs. 87 */ 88 public static File [] pathToFiles (final String [] path, final boolean canonical) 89 { 90 if (path == null) throw new IllegalArgumentException ("null input: path"); 91 if (path.length == 0) return IConstants.EMPTY_FILE_ARRAY; 92 93 final List /* Files */ _result = new ArrayList (path.length); 94 final Set /* String */ pathnames = new HashSet (path.length); 95 96 final String separators = ",".concat (File.pathSeparator); 97 98 for (int i = 0; i < path.length; ++ i) 99 { 100 String segment = path [i]; 101 if (segment == null) throw new IllegalArgumentException ("null input: path[" + i + "]"); 102 103 final StringTokenizer tokenizer = new StringTokenizer (segment, separators); 104 while (tokenizer.hasMoreTokens ()) 105 { 106 String pathname = tokenizer.nextToken (); 107 108 if (canonical) pathname = canonicalizePathname (pathname); 109 110 if (pathnames.add (pathname)) 111 { 112 _result.add (new File (pathname)); 113 } 114 } 115 } 116 117 final File [] result = new File [_result.size ()]; 118 _result.toArray (result); 119 120 return result; 121 } 122 123 /** 124 * Converts 'pathname' into the canonical OS form. This wrapper function 125 * will return the absolute form of 'pathname' if File.getCanonicalPath() fails. 126 */ 127 public static String canonicalizePathname (final String pathname) 128 { 129 if (pathname == null) throw new IllegalArgumentException ("null input: pathname"); 130 131 try 132 { 133 return new File (pathname).getCanonicalPath (); 134 } 135 catch (Exception e) 136 { 137 return new File (pathname).getAbsolutePath (); 138 } 139 } 140 141 public static File canonicalizeFile (final File file) 142 { 143 if (file == null) throw new IllegalArgumentException ("null input: file"); 144 145 try 146 { 147 return file.getCanonicalFile (); 148 } 149 catch (Exception e) 150 { 151 return file.getAbsoluteFile (); 152 } 153 } 154 155 /** 156 * Invariant: (getFileName (file) + getFileExtension (file)).equals (file.getName ()). 157 * 158 * @param file File input file descriptor [must be non-null] 159 * 160 * @return String file name without the extension [excluding '.' separator] 161 * [if 'file' does not appear to have an extension, the full name is returned]. 162 * 163 * @throws IllegalArgumentException if 'file' is null 164 */ 165 public static String getFileName (final File file) 166 { 167 if (file == null) throw new IllegalArgumentException ("null input: file"); 168 169 final String name = file.getName (); 170 int lastDot = name.lastIndexOf ('.'); 171 if (lastDot < 0) return name; 172 173 return name.substring (0, lastDot); 174 } 175 176 /** 177 * Invariant: (getFileName (file) + getFileExtension (file)).equals (file.getName ()). 178 * 179 * @param file File input file descriptor [must be non-null] 180 * 181 * @return String extension [including '.' separator] or "" if 'file' does not 182 * appear to have an extension. 183 * 184 * @throws IllegalArgumentException if 'file' is null 185 */ 186 public static String getFileExtension (final File file) 187 { 188 if (file == null) throw new IllegalArgumentException ("null input: file"); 189 190 final String name = file.getName (); 191 int lastDot = name.lastIndexOf ('.'); 192 if (lastDot < 0) return ""; 193 194 return name.substring (lastDot); 195 } 196 197 /** 198 * 199 * @param dir [null is ignored] 200 * @param file [absolute overrides 'dir'] 201 * @return 202 */ 203 public static File newFile (final File dir, final File file) 204 { 205 if (file == null) throw new IllegalArgumentException ("null input: file"); 206 207 if ((dir == null) || file.isAbsolute ()) return file; 208 209 return new File (dir, file.getPath ()); 210 } 211 212 /** 213 * 214 * @param dir [null is ignored] 215 * @param file [absolute overrides 'dir'] 216 * @return 217 */ 218 public static File newFile (final File dir, final String file) 219 { 220 if (file == null) throw new IllegalArgumentException ("null input: file"); 221 222 final File fileFile = new File (file); 223 if ((dir == null) || fileFile.isAbsolute ()) return fileFile; 224 225 return new File (dir, file); 226 } 227 228 /** 229 * 230 * @param dir [null is ignored] 231 * @param file [absolute overrides 'dir'] 232 * @return 233 */ 234 public static File newFile (final String dir, final String file) 235 { 236 if (file == null) throw new IllegalArgumentException ("null input: file"); 237 238 final File fileFile = new File (file); 239 if ((dir == null) || fileFile.isAbsolute ()) return fileFile; 240 241 return new File (dir, file); 242 } 243 244 /** 245 * Renames 'source' to 'target' [intermediate directories are created if necessary]. If 246 * 'target' exists and 'overwrite' is false, the method is a no-op. No exceptions are 247 * thrown except for when input is invalid. If the operation fails half-way it can leave 248 * some file system artifacts behind. 249 * 250 * @return true iff the renaming was actually performed. 251 * 252 * @param source file descriptor [file must exist] 253 * @param target target file descriptor [an existing target may get deleted 254 * if 'overwrite' is true] 255 * @param overwrite if 'true', forces an existing target to be deleted 256 * 257 * @throws IllegalArgumentException if 'source' is null or file does not exist 258 * @throws IllegalArgumentException if 'target' is null 259 */ 260 public static boolean renameFile (final File source, final File target, final boolean overwrite) 261 { 262 if ((source == null) || ! source.exists ()) 263 throw new IllegalArgumentException ("invalid input source: [" + source + "]"); 264 if (target == null) 265 throw new IllegalArgumentException ("null input: target"); 266 267 final boolean targetExists; 268 if (! (targetExists = target.exists ()) || overwrite) 269 { 270 if (targetExists) 271 { 272 // need to delete the target first or the rename will fail: 273 target.delete (); // not checking the result here: let the rename fail later 274 } 275 else 276 { 277 // note that File.renameTo() does not create intermediate directories on demand: 278 final File targetDir = target.getParentFile (); 279 if ((targetDir != null) && ! targetDir.equals (source.getParentFile ())) 280 targetDir.mkdirs (); // TODO: clean this up on failure? 281 } 282 283 // note: this can fail for a number of reasons, including the target 284 // being on a different drive/file system: 285 return source.renameTo (target); 286 } 287 288 return false; 289 } 290 291 /** 292 * A slightly stricter version of File.createTempFile() in J2SDK 1.3: it requires 293 * that the caller provide an existing parent directory for the temp file. 294 * This defers to File.createTempFile (prefix, extension, parentDir) after 295 * normalizing 'extension'.<P> 296 * 297 * MT-safety: if several threads use this API concurrently, the temp files 298 * created are guaranteed to get created without any collisions and correspond 299 * to files that did not exist before. However, if such a temp file is deleted 300 * at a later point, this method may reuse its file name. These MT-safety 301 * guarantees do not hold if files are created in the same directory outside 302 * of this method. 303 * 304 * @param parentDir parent dir for the temp file [may not be null and must exist] 305 * @param prefix prefix pattern for the temp file name [only the first 3 306 * chars are guaranteed to be used] 307 * @param extension pattern for the temp file name [null is equivalient to 308 * ".tmp"; this is always normalized to start with "."; only the first 3 309 * non-"." chars are guaranteed to be used] 310 * 311 * @return writeable temp file descriptor [incorporates 'parentDir' in its pathname] 312 * @throws IOException if a temp file could not be created 313 */ 314 public static File createTempFile (final File parentDir, final String prefix, String extension) 315 throws IOException 316 { 317 if ((parentDir == null) || ! parentDir.exists ()) 318 throw new IllegalArgumentException ("invalid parent directory: [" + parentDir + "]"); 319 if ((prefix == null) || (prefix.length () < 3)) 320 throw new IllegalArgumentException ("null or less than 3 chars long: " + prefix); 321 322 if (extension == null) extension = ".tmp"; 323 else if (extension.charAt (0) != '.') extension = ".".concat (extension); 324 325 return File.createTempFile (prefix, extension, parentDir); 326 } 327 328 // protected: ............................................................. 329 330 // package: ............................................................... 331 332 // private: ............................................................... 333 334 335 private Files () {} // prevent subclassing 336 337 } // end of class 338 // ----------------------------------------------------------------------------