Home | History | Annotate | Download | only in util
      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 // ----------------------------------------------------------------------------