Return-Path:
Methods exist to retrieve the components of a typical file path. For example
+ * Path-related methods
+ *
+ * /www/hosted/mysite/index.html
, can be broken into:
+ *
+ *
+ * There are also methods to {@link #catPath concatenate two paths}, {@link #resolveFile resolve a
+ * path relative to a File} and {@link #normalize} a path.
+ * /www/hosted/mysite/
-- retrievable through {@link #getPath}index.html
-- retrievable through {@link #removePath}/www/hosted/mysite/index
-- retrievable through {@link #removeExtension}html
-- retrievable through {@link #getExtension}
":", "*", "?", "\"", "<", ">", "|"
+ *
+ * @see
+ * http://support.microsoft.com/?scid=kb%3Ben-us%3B177506&x=12&y=13
+ */
+ private static final String[] INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME = { ":", "*", "?", "\"", "<", ">", "|" };
+
+ /**
+ * @return the default excludes pattern
+ * @see DirectoryScanner#DEFAULTEXCLUDES
+ */
+ public static String[] getDefaultExcludes()
+ {
+ return DirectoryScanner.DEFAULTEXCLUDES;
+ }
+
+ /**
+ * @return the default excludes pattern as list.
+ * @see #getDefaultExcludes()
+ */
+ public static List getDefaultExcludesAsList()
+ {
+ return Arrays.asList( getDefaultExcludes() );
+ }
+
+ /**
+ * @return the default excludes pattern as comma separated string.
+ * @see DirectoryScanner#DEFAULTEXCLUDES
+ * @see StringUtils#join(Object[], String)
+ */
+ public static String getDefaultExcludesAsString()
+ {
+ return StringUtils.join( DirectoryScanner.DEFAULTEXCLUDES, "," );
+ }
+
+ /**
+ * Returns a human-readable version of the file size (original is in
+ * bytes).
+ *
+ * @param size The number of bytes.
+ * @return A human-readable display value (includes units).
+ */
+ public static String byteCountToDisplaySize( int size )
+ {
+ String displaySize;
+
+ if ( size / ONE_GB > 0 )
+ {
+ displaySize = String.valueOf( size / ONE_GB ) + " GB";
+ }
+ else if ( size / ONE_MB > 0 )
+ {
+ displaySize = String.valueOf( size / ONE_MB ) + " MB";
+ }
+ else if ( size / ONE_KB > 0 )
+ {
+ displaySize = String.valueOf( size / ONE_KB ) + " KB";
+ }
+ else
+ {
+ displaySize = String.valueOf( size ) + " bytes";
+ }
+
+ return displaySize;
+ }
+
+ /**
+ * Returns the directory path portion of a file specification string.
+ * Matches the equally named unix command.
+ *
+ * @param filename the file path
+ * @return The directory portion excluding the ending file separator.
+ */
+ public static String dirname( String filename )
+ {
+ int i = filename.lastIndexOf( File.separator );
+ return ( i >= 0 ? filename.substring( 0, i ) : "" );
+ }
+
+ /**
+ * Returns the filename portion of a file specification string.
+ *
+ * @param filename the file path
+ * @return The filename string with extension.
+ */
+ public static String filename( String filename )
+ {
+ int i = filename.lastIndexOf( File.separator );
+ return ( i >= 0 ? filename.substring( i + 1 ) : filename );
+ }
+
+ /**
+ * Returns the filename portion of a file specification string.
+ * Matches the equally named unix command.
+ *
+ * @param filename the file path
+ * @return The filename string without extension.
+ */
+ public static String basename( String filename )
+ {
+ return basename( filename, extension( filename ) );
+ }
+
+ /**
+ * Returns the filename portion of a file specification string.
+ * Matches the equally named unix command.
+ *
+ * @param filename the file path
+ * @param suffix the file suffix
+ * @return the basename of the file
+ */
+ public static String basename( String filename, String suffix )
+ {
+ int i = filename.lastIndexOf( File.separator ) + 1;
+ int lastDot = ( ( suffix != null ) && ( suffix.length() > 0 ) ) ? filename.lastIndexOf( suffix ) : -1;
+
+ if ( lastDot >= 0 )
+ {
+ return filename.substring( i, lastDot );
+ }
+ else if ( i > 0 )
+ {
+ return filename.substring( i );
+ }
+ else
+ {
+ return filename; // else returns all (no path and no extension)
+ }
+ }
+
+ /**
+ * Returns the extension portion of a file specification string.
+ * This everything after the last dot '.' in the filename (NOT including
+ * the dot).
+ *
+ * @param filename the file path
+ * @return the extension of the file
+ */
+ public static String extension( String filename )
+ {
+ // Ensure the last dot is after the last file separator
+ int lastSep = filename.lastIndexOf( File.separatorChar );
+ int lastDot;
+ if ( lastSep < 0 )
+ {
+ lastDot = filename.lastIndexOf( '.' );
+ }
+ else
+ {
+ lastDot = filename.substring( lastSep + 1 ).lastIndexOf( '.' );
+ if ( lastDot >= 0 )
+ {
+ lastDot += lastSep + 1;
+ }
+ }
+
+ if ( lastDot >= 0 && lastDot > lastSep)
+ {
+ return filename.substring( lastDot + 1 );
+ }
+
+ return "";
+ }
+
+ /**
+ * Check if a file exits.
+ *
+ * @param fileName the file path.
+ * @return true if file exists.
+ */
+ public static boolean fileExists( String fileName )
+ {
+ File file = new File( fileName );
+ return file.exists();
+ }
+
+ /**
+ * Note: the file content is read with platform encoding.
+ *
+ * @param file the file path
+ * @return the file content using the platform encoding.
+ * @throws IOException if any
+ */
+ public static String fileRead( String file )
+ throws IOException
+ {
+ return fileRead( file, null );
+ }
+
+ /**
+ * @param file the file path
+ * @param encoding the wanted encoding
+ * @return the file content using the specified encoding.
+ * @throws IOException if any
+ */
+ public static String fileRead( String file, String encoding )
+ throws IOException
+ {
+ return fileRead( new File( file ), encoding );
+ }
+
+ /**
+ * Note: the file content is read with platform encoding
+ *
+ * @param file the file path
+ * @return the file content using the platform encoding.
+ * @throws IOException if any
+ */
+ public static String fileRead( File file )
+ throws IOException
+ {
+ return fileRead( file, null);
+ }
+
+ /**
+ * @param file the file path
+ * @param encoding the wanted encoding
+ * @return the file content using the specified encoding.
+ * @throws IOException if any
+ */
+ public static String fileRead( File file, String encoding )
+ throws IOException
+ {
+ StringBuffer buf = new StringBuffer();
+
+ Reader reader = null;
+
+ try
+ {
+ if ( encoding != null )
+ {
+ reader = new InputStreamReader( new FileInputStream( file ), encoding );
+ }
+ else
+ {
+ reader = new InputStreamReader( new FileInputStream( file ) );
+ }
+ int count;
+ char[] b = new char[512];
+ while ( ( count = reader.read( b ) ) > 0 ) // blocking read
+ {
+ buf.append( b, 0, count );
+ }
+ }
+ finally
+ {
+ IOUtil.close( reader );
+ }
+
+ return buf.toString();
+ }
+
+ /**
+ * Appends data to a file. The file will be created if it does not exist.
+ * Note: the data is written with platform encoding
+ *
+ * @param fileName The path of the file to write.
+ * @param data The content to write to the file.
+ * @throws IOException if any
+ */
+ public static void fileAppend( String fileName, String data )
+ throws IOException
+ {
+ fileAppend( fileName, null, data);
+ }
+
+ /**
+ * Appends data to a file. The file will be created if it does not exist.
+ *
+ * @param fileName The path of the file to write.
+ * @param encoding The encoding of the file.
+ * @param data The content to write to the file.
+ * @throws IOException if any
+ */
+ public static void fileAppend( String fileName, String encoding, String data )
+ throws IOException
+ {
+ FileOutputStream out = null;
+ try
+ {
+ out = new FileOutputStream( fileName, true );
+ if ( encoding != null ) {
+ out.write( data.getBytes( encoding ) );
+ }
+ else
+ {
+ out.write( data.getBytes() );
+ }
+ }
+ finally
+ {
+ IOUtil.close( out );
+ }
+ }
+
+ /**
+ * Writes data to a file. The file will be created if it does not exist.
+ * Note: the data is written with platform encoding
+ *
+ * @param fileName The path of the file to write.
+ * @param data The content to write to the file.
+ * @throws IOException if any
+ */
+ public static void fileWrite( String fileName, String data )
+ throws IOException
+ {
+ fileWrite( fileName, null, data );
+ }
+
+ /**
+ * Writes data to a file. The file will be created if it does not exist.
+ *
+ * @param fileName The path of the file to write.
+ * @param encoding The encoding of the file.
+ * @param data The content to write to the file.
+ * @throws IOException if any
+ */
+ public static void fileWrite( String fileName, String encoding, String data )
+ throws IOException
+ {
+ FileOutputStream out = null;
+ try
+ {
+ out = new FileOutputStream( fileName );
+ if ( encoding != null )
+ {
+ out.write( data.getBytes( encoding ) );
+ }
+ else
+ {
+ out.write( data.getBytes() );
+ }
+ }
+ finally
+ {
+ IOUtil.close( out );
+ }
+ }
+
+ /**
+ * Deletes a file.
+ *
+ * @param fileName The path of the file to delete.
+ */
+ public static void fileDelete( String fileName )
+ {
+ File file = new File( fileName );
+ file.delete();
+ }
+
+ /**
+ * Waits for NFS to propagate a file creation, imposing a timeout.
+ *
+ * @param fileName The path of the file.
+ * @param seconds The maximum time in seconds to wait.
+ * @return True if file exists.
+ */
+ public static boolean waitFor( String fileName, int seconds )
+ {
+ return waitFor( new File( fileName ), seconds );
+ }
+
+ /**
+ * Waits for NFS to propagate a file creation, imposing a timeout.
+ *
+ * @param file The file.
+ * @param seconds The maximum time in seconds to wait.
+ * @return True if file exists.
+ */
+ public static boolean waitFor( File file, int seconds )
+ {
+ int timeout = 0;
+ int tick = 0;
+ while ( !file.exists() )
+ {
+ if ( tick++ >= 10 )
+ {
+ tick = 0;
+ if ( timeout++ > seconds )
+ {
+ return false;
+ }
+ }
+ try
+ {
+ Thread.sleep( 100 );
+ }
+ catch ( InterruptedException ignore )
+ {
+ // nop
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Creates a file handle.
+ *
+ * @param fileName The path of the file.
+ * @return A File
manager.
+ */
+ public static File getFile( String fileName )
+ {
+ return new File( fileName );
+ }
+
+ /**
+ * Given a directory and an array of extensions return an array of compliant files.
+ *
+ * TODO Should an ignore list be passed in?
+ * TODO Should a recurse flag be passed in?
+ *
+ * The given extensions should be like "java" and not like ".java"
+ *
+ * @param directory The path of the directory.
+ * @param extensions an array of expected extensions.
+ * @return An array of files for the wanted extensions.
+ */
+ public static String[] getFilesFromExtension( String directory, String[] extensions )
+ {
+ Vector files = new Vector();
+
+ File currentDir = new File( directory );
+
+ String[] unknownFiles = currentDir.list();
+
+ if ( unknownFiles == null )
+ {
+ return new String[0];
+ }
+
+ for ( int i = 0; i < unknownFiles.length; ++i )
+ {
+ String currentFileName = directory + System.getProperty( "file.separator" ) + unknownFiles[i];
+ File currentFile = new File( currentFileName );
+
+ if ( currentFile.isDirectory() )
+ {
+ //ignore all CVS directories...
+ if ( currentFile.getName().equals( "CVS" ) )
+ {
+ continue;
+ }
+
+ //ok... transverse into this directory and get all the files... then combine
+ //them with the current list.
+
+ String[] fetchFiles = getFilesFromExtension( currentFileName, extensions );
+ files = blendFilesToVector( files, fetchFiles );
+ }
+ else
+ {
+ //ok... add the file
+
+ String add = currentFile.getAbsolutePath();
+ if ( isValidFile( add, extensions ) )
+ {
+ files.addElement( add );
+ }
+ }
+ }
+
+ //ok... move the Vector into the files list...
+ String[] foundFiles = new String[files.size()];
+ files.copyInto( foundFiles );
+
+ return foundFiles;
+ }
+
+ /**
+ * Private helper method for getFilesFromExtension()
+ */
+ private static Vector blendFilesToVector( Vector v, String[] files )
+ {
+ for ( int i = 0; i < files.length; ++i )
+ {
+ v.addElement( files[i] );
+ }
+
+ return v;
+ }
+
+ /**
+ * Checks to see if a file is of a particular type(s).
+ * Note that if the file does not have an extension, an empty string
+ * ("") is matched for.
+ */
+ private static boolean isValidFile( String file, String[] extensions )
+ {
+ String extension = extension( file );
+ if ( extension == null )
+ {
+ extension = "";
+ }
+
+ //ok.. now that we have the "extension" go through the current know
+ //excepted extensions and determine if this one is OK.
+
+ for ( int i = 0; i < extensions.length; ++i )
+ {
+ if ( extensions[i].equals( extension ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+
+ }
+
+ /**
+ * Simple way to make a directory
+ *
+ * @param dir the directory to create
+ * @throws IllegalArgumentException if the dir contains illegal Windows characters under Windows OS.
+ * @see #INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME
+ */
+ public static void mkdir( String dir )
+ {
+ File file = new File( dir );
+
+ if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
+ {
+ if ( !isValidWindowsFileName( file ) )
+ {
+ throw new IllegalArgumentException( "The file (" + dir
+ + ") cannot contain any of the following characters: \n"
+ + StringUtils.join( INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME, " " ) );
+ }
+ }
+
+ if ( !file.exists() )
+ {
+ file.mkdirs();
+ }
+ }
+
+ /**
+ * Compare the contents of two files to determine if they are equal or not.
+ *
+ * @param file1 the first file
+ * @param file2 the second file
+ * @return true if the content of the files are equal or they both don't exist, false otherwise
+ * @throws IOException if any
+ */
+ public static boolean contentEquals( final File file1, final File file2 )
+ throws IOException
+ {
+ final boolean file1Exists = file1.exists();
+ if ( file1Exists != file2.exists() )
+ {
+ return false;
+ }
+
+ if ( !file1Exists )
+ {
+ // two not existing files are equal
+ return true;
+ }
+
+ if ( file1.isDirectory() || file2.isDirectory() )
+ {
+ // don't want to compare directory contents
+ return false;
+ }
+
+ InputStream input1 = null;
+ InputStream input2 = null;
+ try
+ {
+ input1 = new FileInputStream( file1 );
+ input2 = new FileInputStream( file2 );
+ return IOUtil.contentEquals( input1, input2 );
+
+ }
+ finally
+ {
+ IOUtil.close( input1 );
+ IOUtil.close( input2 );
+ }
+ }
+
+ /**
+ * Convert from a URL
to a File
.
+ *
+ * @param url File URL.
+ * @return The equivalent File
object, or null
if the URL's protocol
+ * is not file
+ */
+ public static File toFile( final URL url )
+ {
+ if ( url == null || !url.getProtocol().equalsIgnoreCase( "file" ) )
+ {
+ return null;
+ }
+
+ String filename = url.getFile().replace( '/', File.separatorChar );
+ int pos = -1;
+ while ( ( pos = filename.indexOf( '%', pos + 1 ) ) >= 0 )
+ {
+ if ( pos + 2 < filename.length() )
+ {
+ String hexStr = filename.substring( pos + 1, pos + 3 );
+ char ch = (char) Integer.parseInt( hexStr, 16 );
+ filename = filename.substring( 0, pos ) + ch + filename.substring( pos + 3 );
+ }
+ }
+ return new File( filename );
+ }
+
+ /**
+ * Convert the array of Files into a list of URLs.
+ *
+ * @param files the array of files
+ * @return the array of URLs
+ * @throws IOException if an error occurs
+ */
+ public static URL[] toURLs( final File[] files )
+ throws IOException
+ {
+ final URL[] urls = new URL[files.length];
+
+ for ( int i = 0; i < urls.length; i++ )
+ {
+ urls[i] = files[i].toURL();
+ }
+
+ return urls;
+ }
+
+ /**
+ * Remove extension from filename.
+ * ie
+ * + * foo.txt --> foo + * a\b\c.jpg --> a\b\c + * a\b\c --> a\b\c + *+ * + * @param filename the path of the file + * @return the filename minus extension + */ + public static String removeExtension( final String filename ) + { + String ext = extension(filename); + + if ( "".equals(ext) ) + { + return filename; + } + + final int index = filename.lastIndexOf( ext ) - 1; + return filename.substring( 0, index ); + } + + /** + * Get extension from filename. + * ie + *
+ * foo.txt --> "txt" + * a\b\c.jpg --> "jpg" + * a\b\c --> "" + *+ * + * @param filename the path of the file + * @return the extension of filename or "" if none + */ + public static String getExtension( final String filename ) + { + return extension(filename); + } + + /** + * Remove path from filename. Equivalent to the unix command
basename
+ * ie.
+ * + * a/b/c.txt --> c.txt + * a.txt --> a.txt + *+ * + * @param filepath the path of the file + * @return the filename minus path + */ + public static String removePath( final String filepath ) + { + return removePath( filepath, File.separatorChar ); + } + + /** + * Remove path from filename. + * ie. + *
+ * a/b/c.txt --> c.txt + * a.txt --> a.txt + *+ * + * @param filepath the path of the file + * @param fileSeparatorChar the file separator character like / on Unix plateforms. + * @return the filename minus path + */ + public static String removePath( final String filepath, final char fileSeparatorChar ) + { + final int index = filepath.lastIndexOf( fileSeparatorChar ); + + if ( -1 == index ) + { + return filepath; + } + + return filepath.substring( index + 1 ); + } + + /** + * Get path from filename. Roughly equivalent to the unix command
dirname
.
+ * ie.
+ * + * a/b/c.txt --> a/b + * a.txt --> "" + *+ * + * @param filepath the filepath + * @return the filename minus path + */ + public static String getPath( final String filepath ) + { + return getPath( filepath, File.separatorChar ); + } + + /** + * Get path from filename. + * ie. + *
+ * a/b/c.txt --> a/b + * a.txt --> "" + *+ * + * @param filepath the filepath + * @param fileSeparatorChar the file separator character like / on Unix plateforms. + * @return the filename minus path + */ + public static String getPath( final String filepath, final char fileSeparatorChar ) + { + final int index = filepath.lastIndexOf( fileSeparatorChar ); + if ( -1 == index ) + { + return ""; + } + + return filepath.substring( 0, index ); + } + + /** + * Copy file from source to destination. If
destinationDirectory
does not exist, it
+ * (and any parent directories) will be created. If a file source
in
+ * destinationDirectory
exists, it will be overwritten.
+ *
+ * @param source An existing File
to copy.
+ * @param destinationDirectory A directory to copy source
into.
+ * @throws java.io.FileNotFoundException if source
isn't a normal file.
+ * @throws IllegalArgumentException if destinationDirectory
isn't a directory.
+ * @throws IOException if source
does not exist, the file in
+ * destinationDirectory
cannot be written to, or an IO error occurs during copying.
+ */
+ public static void copyFileToDirectory( final String source, final String destinationDirectory )
+ throws IOException
+ {
+ copyFileToDirectory( new File( source ), new File( destinationDirectory ) );
+ }
+
+ /**
+ * Copy file from source to destination only if source is newer than the target file.
+ * If destinationDirectory
does not exist, it
+ * (and any parent directories) will be created. If a file source
in
+ * destinationDirectory
exists, it will be overwritten.
+ *
+ * @param source An existing File
to copy.
+ * @param destinationDirectory A directory to copy source
into.
+ * @throws java.io.FileNotFoundException if source
isn't a normal file.
+ * @throws IllegalArgumentException if destinationDirectory
isn't a directory.
+ * @throws IOException if source
does not exist, the file in
+ * destinationDirectory
cannot be written to, or an IO error occurs during copying.
+ */
+ public static void copyFileToDirectoryIfModified( final String source, final String destinationDirectory )
+ throws IOException
+ {
+ copyFileToDirectoryIfModified( new File( source ), new File( destinationDirectory ) );
+ }
+
+ /**
+ * Copy file from source to destination. If destinationDirectory
does not exist, it
+ * (and any parent directories) will be created. If a file source
in
+ * destinationDirectory
exists, it will be overwritten.
+ *
+ * @param source An existing File
to copy.
+ * @param destinationDirectory A directory to copy source
into.
+ * @throws java.io.FileNotFoundException if source
isn't a normal file.
+ * @throws IllegalArgumentException if destinationDirectory
isn't a directory.
+ * @throws IOException if source
does not exist, the file in
+ * destinationDirectory
cannot be written to, or an IO error occurs during copying.
+ */
+ public static void copyFileToDirectory( final File source, final File destinationDirectory )
+ throws IOException
+ {
+ if ( destinationDirectory.exists() && !destinationDirectory.isDirectory() )
+ {
+ throw new IllegalArgumentException( "Destination is not a directory" );
+ }
+
+ copyFile( source, new File( destinationDirectory, source.getName() ) );
+ }
+
+ /**
+ * Copy file from source to destination only if source is newer than the target file.
+ * If destinationDirectory
does not exist, it
+ * (and any parent directories) will be created. If a file source
in
+ * destinationDirectory
exists, it will be overwritten.
+ *
+ * @param source An existing File
to copy.
+ * @param destinationDirectory A directory to copy source
into.
+ * @throws java.io.FileNotFoundException if source
isn't a normal file.
+ * @throws IllegalArgumentException if destinationDirectory
isn't a directory.
+ * @throws IOException if source
does not exist, the file in
+ * destinationDirectory
cannot be written to, or an IO error occurs during copying.
+ */
+ public static void copyFileToDirectoryIfModified( final File source, final File destinationDirectory )
+ throws IOException
+ {
+ if ( destinationDirectory.exists() && !destinationDirectory.isDirectory() )
+ {
+ throw new IllegalArgumentException( "Destination is not a directory" );
+ }
+
+ copyFileIfModified( source, new File( destinationDirectory, source.getName() ) );
+ }
+
+
+ /**
+ * Copy file from source to destination. The directories up to destination
will be
+ * created if they don't already exist. destination
will be overwritten if it
+ * already exists.
+ *
+ * @param source An existing non-directory File
to copy bytes from.
+ * @param destination A non-directory File
to write bytes to (possibly
+ * overwriting).
+ * @throws IOException if source
does not exist, destination
cannot be
+ * written to, or an IO error occurs during copying.
+ * @throws java.io.FileNotFoundException if destination
is a directory
+ * (use {@link #copyFileToDirectory}).
+ */
+ public static void copyFile( final File source, final File destination )
+ throws IOException
+ {
+ //check source exists
+ if ( !source.exists() )
+ {
+ final String message = "File " + source + " does not exist";
+ throw new IOException( message );
+ }
+
+ //check source != destination, see PLXUTILS-10
+ if ( source.getCanonicalPath().equals( destination.getCanonicalPath() ) )
+ {
+ //if they are equal, we can exit the method without doing any work
+ return;
+ }
+
+ copyStreamToFile( new FileInputStreamFacade( source ), destination);
+
+ if ( source.length() != destination.length() )
+ {
+ final String message = "Failed to copy full contents from " + source + " to " + destination;
+ throw new IOException( message );
+ }
+ }
+
+ /**
+ * Copy file from source to destination only if source timestamp is later than the destination timestamp.
+ * The directories up to destination
will be created if they don't already exist.
+ * destination
will be overwritten if it already exists.
+ *
+ * @param source An existing non-directory File
to copy bytes from.
+ * @param destination A non-directory File
to write bytes to (possibly
+ * overwriting).
+ * @return true if no problem occured
+ * @throws IOException if source
does not exist, destination
cannot be
+ * written to, or an IO error occurs during copying.
+ * @throws FileNotFoundException if destination
is a directory
+ * (use {@link #copyFileToDirectory}).
+ */
+ public static boolean copyFileIfModified( final File source, final File destination )
+ throws IOException
+ {
+ if ( destination.lastModified() < source.lastModified() )
+ {
+ copyFile( source, destination );
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Copies bytes from the URL source
to a file destination
.
+ * The directories up to destination
will be created if they don't already exist.
+ * destination
will be overwritten if it already exists.
+ *
+ * @param source A URL
to copy bytes from.
+ * @param destination A non-directory File
to write bytes to (possibly
+ * overwriting).
+ * @throws IOException if
+ * source
URL cannot be openeddestination
cannot be written tosource
to a file destination
.
+ * The directories up to destination
will be created if they don't already exist.
+ * destination
will be overwritten if it already exists.
+ *
+ * @param source An {@link InputStream} to copy bytes from. This stream is
+ * guaranteed to be closed.
+ * @param destination A non-directory File
to write bytes to (possibly
+ * overwriting).
+ * @throws IOException if
+ * source
URL cannot be openeddestination
cannot be written tonull
if the ..'s went past the
+ * root.
+ * Eg:
+ * + * /foo// --> /foo/ + * /foo/./ --> /foo/ + * /foo/../bar --> /bar + * /foo/../bar/ --> /bar/ + * /foo/../bar/../baz --> /baz + * //foo//./bar --> /foo/bar + * /../ --> null + *+ * + * @param path the path to normalize + * @return the normalized String, or
null
if too many ..'s.
+ */
+ public static String normalize( final String path )
+ {
+ String normalized = path;
+ // Resolve occurrences of "//" in the normalized path
+ while ( true )
+ {
+ int index = normalized.indexOf( "//" );
+ if ( index < 0 )
+ {
+ break;
+ }
+ normalized = normalized.substring( 0, index ) + normalized.substring( index + 1 );
+ }
+
+ // Resolve occurrences of "/./" in the normalized path
+ while ( true )
+ {
+ int index = normalized.indexOf( "/./" );
+ if ( index < 0 )
+ {
+ break;
+ }
+ normalized = normalized.substring( 0, index ) + normalized.substring( index + 2 );
+ }
+
+ // Resolve occurrences of "/../" in the normalized path
+ while ( true )
+ {
+ int index = normalized.indexOf( "/../" );
+ if ( index < 0 )
+ {
+ break;
+ }
+ if ( index == 0 )
+ {
+ return null; // Trying to go outside our context
+ }
+ int index2 = normalized.lastIndexOf( '/', index - 1 );
+ normalized = normalized.substring( 0, index2 ) + normalized.substring( index + 3 );
+ }
+
+ // Return the normalized path that we have completed
+ return normalized;
+ }
+
+ /**
+ * Will concatenate 2 paths. Paths with ..
will be
+ * properly handled.
+ * Eg.,
+ * /a/b/c
+ d
= /a/b/d
+ * /a/b/c
+ ../d
= /a/d
+ *
filename
to it's canonical form. If filename
is
+ * relative (doesn't start with /
), it will be resolved relative to
+ * baseFile
, otherwise it is treated as a normal root-relative path.
+ *
+ * @param baseFile Where to resolve filename
from, if filename
is
+ * relative.
+ * @param filename Absolute or relative file path to resolve.
+ * @return The canonical File
of filename
.
+ */
+ public static File resolveFile( final File baseFile, String filename )
+ {
+ String filenm = filename;
+ if ( '/' != File.separatorChar )
+ {
+ filenm = filename.replace( '/', File.separatorChar );
+ }
+
+ if ( '\\' != File.separatorChar )
+ {
+ filenm = filename.replace( '\\', File.separatorChar );
+ }
+
+ // deal with absolute files
+ if ( filenm.startsWith( File.separator ) || ( Os.isFamily( Os.FAMILY_WINDOWS ) && filenm.indexOf( ":" ) > 0 ) )
+ {
+ File file = new File( filenm );
+
+ try
+ {
+ file = file.getCanonicalFile();
+ }
+ catch ( final IOException ioe )
+ {
+ // nop
+ }
+
+ return file;
+ }
+ // FIXME: I'm almost certain this // removal is unnecessary, as getAbsoluteFile() strips
+ // them. However, I'm not sure about this UNC stuff. (JT)
+ final char[] chars = filename.toCharArray();
+ final StringBuffer sb = new StringBuffer();
+
+ //remove duplicate file separators in succession - except
+ //on win32 at start of filename as UNC filenames can
+ //be \\AComputer\AShare\myfile.txt
+ int start = 0;
+ if ( '\\' == File.separatorChar )
+ {
+ sb.append( filenm.charAt( 0 ) );
+ start++;
+ }
+
+ for ( int i = start; i < chars.length; i++ )
+ {
+ final boolean doubleSeparator = File.separatorChar == chars[i] && File.separatorChar == chars[i - 1];
+
+ if ( !doubleSeparator )
+ {
+ sb.append( chars[i] );
+ }
+ }
+
+ filenm = sb.toString();
+
+ //must be relative
+ File file = ( new File( baseFile, filenm ) ).getAbsoluteFile();
+
+ try
+ {
+ file = file.getCanonicalFile();
+ }
+ catch ( final IOException ioe )
+ {
+ // nop
+ }
+
+ return file;
+ }
+
+ /**
+ * Delete a file. If file is directory delete it and all sub-directories.
+ *
+ * @param file the file path
+ * @throws IOException if any
+ */
+ public static void forceDelete( final String file )
+ throws IOException
+ {
+ forceDelete( new File( file ) );
+ }
+
+ /**
+ * Delete a file. If file is directory delete it and all sub-directories.
+ *
+ * @param file a file
+ * @throws IOException if any
+ */
+ public static void forceDelete( final File file )
+ throws IOException
+ {
+ if ( file.isDirectory() )
+ {
+ deleteDirectory( file );
+ }
+ else
+ {
+ /*
+ * NOTE: Always try to delete the file even if it appears to be non-existent. This will ensure that a
+ * symlink whose target does not exist is deleted, too.
+ */
+ boolean filePresent = file.getCanonicalFile().exists();
+ if ( !deleteFile( file ) && filePresent )
+ {
+ final String message = "File " + file + " unable to be deleted.";
+ throw new IOException( message );
+ }
+ }
+ }
+
+ /**
+ * Accommodate Windows bug encountered in both Sun and IBM JDKs.
+ * Others possible. If the delete does not work, call System.gc(),
+ * wait a little and try again.
+ *
+ * @param file a file
+ * @throws IOException if any
+ */
+ private static boolean deleteFile( File file )
+ throws IOException
+ {
+ if ( file.isDirectory() )
+ {
+ throw new IOException( "File " + file + " isn't a file." );
+ }
+
+ if ( !file.delete() )
+ {
+ if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
+ {
+ file = file.getCanonicalFile();
+ System.gc();
+ }
+
+ try
+ {
+ Thread.sleep( 10 );
+ return file.delete();
+ }
+ catch ( InterruptedException ex )
+ {
+ return file.delete();
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Schedule a file to be deleted when JVM exits.
+ * If file is directory delete it and all sub-directories.
+ *
+ * @param file a file
+ * @throws IOException if any
+ */
+ public static void forceDeleteOnExit( final File file )
+ throws IOException
+ {
+ if ( !file.exists() )
+ {
+ return;
+ }
+
+ if ( file.isDirectory() )
+ {
+ deleteDirectoryOnExit( file );
+ }
+ else
+ {
+ file.deleteOnExit();
+ }
+ }
+
+ /**
+ * Recursively schedule directory for deletion on JVM exit.
+ *
+ * @param file a directory
+ * @throws IOException if any
+ */
+ private static void deleteDirectoryOnExit( final File directory )
+ throws IOException
+ {
+ if ( !directory.exists() )
+ {
+ return;
+ }
+
+ cleanDirectoryOnExit( directory );
+ directory.deleteOnExit();
+ }
+
+ /**
+ * Clean a directory without deleting it.
+ *
+ * @param file a directory
+ * @throws IOException if any
+ */
+ private static void cleanDirectoryOnExit( final File directory )
+ throws IOException
+ {
+ if ( !directory.exists() )
+ {
+ final String message = directory + " does not exist";
+ throw new IllegalArgumentException( message );
+ }
+
+ if ( !directory.isDirectory() )
+ {
+ final String message = directory + " is not a directory";
+ throw new IllegalArgumentException( message );
+ }
+
+ IOException exception = null;
+
+ final File[] files = directory.listFiles();
+ for ( int i = 0; i < files.length; i++ )
+ {
+ final File file = files[i];
+ try
+ {
+ forceDeleteOnExit( file );
+ }
+ catch ( final IOException ioe )
+ {
+ exception = ioe;
+ }
+ }
+
+ if ( null != exception )
+ {
+ throw exception;
+ }
+ }
+
+
+ /**
+ * Make a directory.
+ *
+ * @param file not null
+ * @throws IOException If there already exists a file with specified name or
+ * the directory is unable to be created
+ * @throws IllegalArgumentException if the file contains illegal Windows characters under Windows OS.
+ * @see #INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME
+ */
+ public static void forceMkdir( final File file )
+ throws IOException
+ {
+ if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
+ {
+ if ( !isValidWindowsFileName( file ) )
+ {
+ throw new IllegalArgumentException( "The file (" + file.getAbsolutePath()
+ + ") cannot contain any of the following characters: \n"
+ + StringUtils.join( INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME, " " ) );
+ }
+ }
+
+ if ( file.exists() )
+ {
+ if ( file.isFile() )
+ {
+ final String message =
+ "File " + file + " exists and is " + "not a directory. Unable to create directory.";
+ throw new IOException( message );
+ }
+ }
+ else
+ {
+ if ( false == file.mkdirs() )
+ {
+ final String message = "Unable to create directory " + file;
+ throw new IOException( message );
+ }
+ }
+ }
+
+ /**
+ * Recursively delete a directory.
+ *
+ * @param directory a directory
+ * @throws IOException if any
+ */
+ public static void deleteDirectory( final String directory )
+ throws IOException
+ {
+ deleteDirectory( new File( directory ) );
+ }
+
+ /**
+ * Recursively delete a directory.
+ *
+ * @param directory a directory
+ * @throws IOException if any
+ */
+ public static void deleteDirectory( final File directory )
+ throws IOException
+ {
+ if ( !directory.exists() )
+ {
+ return;
+ }
+
+ cleanDirectory( directory );
+ if ( !directory.delete() )
+ {
+ final String message = "Directory " + directory + " unable to be deleted.";
+ throw new IOException( message );
+ }
+ }
+
+ /**
+ * Clean a directory without deleting it.
+ *
+ * @param directory a directory
+ * @throws IOException if any
+ */
+ public static void cleanDirectory( final String directory )
+ throws IOException
+ {
+ cleanDirectory( new File( directory ) );
+ }
+
+ /**
+ * Clean a directory without deleting it.
+ *
+ * @param directory a directory
+ * @throws IOException if any
+ */
+ public static void cleanDirectory( final File directory )
+ throws IOException
+ {
+ if ( !directory.exists() )
+ {
+ final String message = directory + " does not exist";
+ throw new IllegalArgumentException( message );
+ }
+
+ if ( !directory.isDirectory() )
+ {
+ final String message = directory + " is not a directory";
+ throw new IllegalArgumentException( message );
+ }
+
+ IOException exception = null;
+
+ final File[] files = directory.listFiles();
+
+ if ( files == null )
+ {
+ return;
+ }
+
+ for ( int i = 0; i < files.length; i++ )
+ {
+ final File file = files[i];
+ try
+ {
+ forceDelete( file );
+ }
+ catch ( final IOException ioe )
+ {
+ exception = ioe;
+ }
+ }
+
+ if ( null != exception )
+ {
+ throw exception;
+ }
+ }
+
+ /**
+ * Recursively count size of a directory.
+ *
+ * @param directory a directory
+ * @return size of directory in bytes.
+ */
+ public static long sizeOfDirectory( final String directory )
+ {
+ return sizeOfDirectory( new File( directory ) );
+ }
+
+ /**
+ * Recursively count size of a directory.
+ *
+ * @param directory a directory
+ * @return size of directory in bytes.
+ */
+ public static long sizeOfDirectory( final File directory )
+ {
+ if ( !directory.exists() )
+ {
+ final String message = directory + " does not exist";
+ throw new IllegalArgumentException( message );
+ }
+
+ if ( !directory.isDirectory() )
+ {
+ final String message = directory + " is not a directory";
+ throw new IllegalArgumentException( message );
+ }
+
+ long size = 0;
+
+ final File[] files = directory.listFiles();
+ for ( int i = 0; i < files.length; i++ )
+ {
+ final File file = files[i];
+
+ if ( file.isDirectory() )
+ {
+ size += sizeOfDirectory( file );
+ }
+ else
+ {
+ size += file.length();
+ }
+ }
+
+ return size;
+ }
+
+ /**
+ * Return the files contained in the directory, using inclusion and exclusion Ant patterns,
+ * including the directory name in each of the files
+ *
+ * @param directory the directory to scan
+ * @param includes the includes pattern, comma separated
+ * @param excludes the excludes pattern, comma separated
+ * @return a list of File objects
+ * @throws IOException
+ * @see #getFileNames( File, String, String, boolean )
+ */
+ public static List getFiles( File directory, String includes, String excludes )
+ throws IOException
+ {
+ return getFiles( directory, includes, excludes, true );
+ }
+
+ /**
+ * Return the files contained in the directory, using inclusion and exclusion Ant patterns
+ *
+ * @param directory the directory to scan
+ * @param includes the includes pattern, comma separated
+ * @param excludes the excludes pattern, comma separated
+ * @param includeBasedir true to include the base dir in each file
+ * @return a list of File objects
+ * @throws IOException
+ * @see #getFileNames( File, String, String, boolean )
+ */
+ public static List getFiles( File directory, String includes, String excludes, boolean includeBasedir )
+ throws IOException
+ {
+ List fileNames = getFileNames( directory, includes, excludes, includeBasedir );
+
+ List files = new ArrayList();
+
+ for ( Iterator i = fileNames.iterator(); i.hasNext(); )
+ {
+ files.add( new File( (String) i.next() ) );
+ }
+
+ return files;
+ }
+
+ /**
+ * Return a list of files as String depending options.
+ * This method use case sensitive file name.
+ *
+ * @param directory the directory to scan
+ * @param includes the includes pattern, comma separated
+ * @param excludes the excludes pattern, comma separated
+ * @param includeBasedir true to include the base dir in each String of file
+ * @return a list of files as String
+ * @throws IOException
+ */
+ public static List getFileNames( File directory, String includes, String excludes, boolean includeBasedir )
+ throws IOException
+ {
+ return getFileNames( directory, includes, excludes, includeBasedir, true );
+ }
+
+ /**
+ * Return a list of files as String depending options.
+ *
+ * @param directory the directory to scan
+ * @param includes the includes pattern, comma separated
+ * @param excludes the excludes pattern, comma separated
+ * @param includeBasedir true to include the base dir in each String of file
+ * @param isCaseSensitive true if case sensitive
+ * @return a list of files as String
+ * @throws IOException
+ */
+ public static List getFileNames( File directory, String includes, String excludes, boolean includeBasedir,
+ boolean isCaseSensitive )
+ throws IOException
+ {
+ return getFileAndDirectoryNames( directory, includes, excludes, includeBasedir, isCaseSensitive, true, false );
+ }
+
+ /**
+ * Return a list of directories as String depending options.
+ * This method use case sensitive file name.
+ *
+ * @param directory the directory to scan
+ * @param includes the includes pattern, comma separated
+ * @param excludes the excludes pattern, comma separated
+ * @param includeBasedir true to include the base dir in each String of file
+ * @return a list of directories as String
+ * @throws IOException
+ */
+ public static List getDirectoryNames( File directory, String includes, String excludes, boolean includeBasedir )
+ throws IOException
+ {
+ return getDirectoryNames( directory, includes, excludes, includeBasedir, true );
+ }
+
+ /**
+ * Return a list of directories as String depending options.
+ *
+ * @param directory the directory to scan
+ * @param includes the includes pattern, comma separated
+ * @param excludes the excludes pattern, comma separated
+ * @param includeBasedir true to include the base dir in each String of file
+ * @param isCaseSensitive true if case sensitive
+ * @return a list of directories as String
+ * @throws IOException
+ */
+ public static List getDirectoryNames( File directory, String includes, String excludes, boolean includeBasedir,
+ boolean isCaseSensitive )
+ throws IOException
+ {
+ return getFileAndDirectoryNames( directory, includes, excludes, includeBasedir, isCaseSensitive, false, true );
+ }
+
+ /**
+ * Return a list of files as String depending options.
+ *
+ * @param directory the directory to scan
+ * @param includes the includes pattern, comma separated
+ * @param excludes the excludes pattern, comma separated
+ * @param includeBasedir true to include the base dir in each String of file
+ * @param isCaseSensitive true if case sensitive
+ * @param getFiles true if get files
+ * @param getDirectories true if get directories
+ * @return a list of files as String
+ * @throws IOException
+ */
+ public static List getFileAndDirectoryNames( File directory, String includes, String excludes,
+ boolean includeBasedir, boolean isCaseSensitive, boolean getFiles,
+ boolean getDirectories )
+ throws IOException
+ {
+ DirectoryScanner scanner = new DirectoryScanner();
+
+ scanner.setBasedir( directory );
+
+ if ( includes != null )
+ {
+ scanner.setIncludes( StringUtils.split( includes, "," ) );
+ }
+
+ if ( excludes != null )
+ {
+ scanner.setExcludes( StringUtils.split( excludes, "," ) );
+ }
+
+ scanner.setCaseSensitive( isCaseSensitive );
+
+ scanner.scan();
+
+ List list = new ArrayList();
+
+ if ( getFiles )
+ {
+ String[] files = scanner.getIncludedFiles();
+
+ for ( int i = 0; i < files.length; i++ )
+ {
+ if ( includeBasedir )
+ {
+ list.add( directory + FileUtils.FS + files[i] );
+ }
+ else
+ {
+ list.add( files[i] );
+ }
+ }
+ }
+
+ if ( getDirectories )
+ {
+ String[] directories = scanner.getIncludedDirectories();
+
+ for ( int i = 0; i < directories.length; i++ )
+ {
+ if ( includeBasedir )
+ {
+ list.add( directory + FileUtils.FS + directories[i] );
+ }
+ else
+ {
+ list.add( directories[i] );
+ }
+ }
+ }
+
+ return list;
+ }
+
+ /**
+ * Copy a directory to an other one.
+ *
+ * @param sourceDirectory the source dir
+ * @param destinationDirectory the target dir
+ * @throws IOException if any
+ */
+ public static void copyDirectory( File sourceDirectory, File destinationDirectory )
+ throws IOException
+ {
+ copyDirectory( sourceDirectory, destinationDirectory, "**", null );
+ }
+
+ /**
+ * Copy a directory to an other one.
+ *
+ * @param sourceDirectory the source dir
+ * @param destinationDirectory the target dir
+ * @param includes include pattern
+ * @param excludes exlucde pattern
+ * @throws IOException if any
+ * @see #getFiles(File, String, String)
+ */
+ public static void copyDirectory( File sourceDirectory, File destinationDirectory, String includes,
+ String excludes )
+ throws IOException
+ {
+ if ( !sourceDirectory.exists() )
+ {
+ return;
+ }
+
+ List files = getFiles( sourceDirectory, includes, excludes );
+
+ for ( Iterator i = files.iterator(); i.hasNext(); )
+ {
+ File file = (File) i.next();
+
+ copyFileToDirectory( file, destinationDirectory );
+ }
+ }
+
+ /**
+ * Copies a entire directory layout : no files will be copied only directories
+ *
+ * Note:
+ * sourceDirectory
must exists.
+ * sourceDirectory
must exists.
+ * sourceDirectory
must exists.
+ * This will remove to
(if it exists), ensure that
+ * to
's parent directory exists and move
+ * from
, which involves deleting from
as
+ * well.
to
may have been deleted already when this happens.
+ */
+ public static void rename( File from, File to )
+ throws IOException
+ {
+ if ( to.exists() && !to.delete() )
+ {
+ throw new IOException( "Failed to delete " + to + " while trying to rename " + from );
+ }
+
+ File parent = to.getParentFile();
+ if ( parent != null && !parent.exists() && !parent.mkdirs() )
+ {
+ throw new IOException( "Failed to create directory " + parent + " while trying to rename " + from );
+ }
+
+ if ( !from.renameTo( to ) )
+ {
+ copyFile( from, to );
+ if ( !from.delete() )
+ {
+ throw new IOException( "Failed to delete " + from + " while trying to rename it." );
+ }
+ }
+ }
+
+ /**
+ * Create a temporary file in a given directory.
+ *
+ * The file denoted by the returned abstract pathname did not + * exist before this method was invoked, any subsequent invocation + * of this method will yield a different file name.
+ * + * The filename is prefixNNNNNsuffix where NNNN is a random number + * + *This method is different to {@link File#createTempFile(String, String, File)} of JDK 1.2 + * as it doesn't create the file itself. + * It uses the location pointed to by java.io.tmpdir + * when the parentDir attribute is + * null.
+ *To delete automatically the file created by this method, use the + * {@link File#deleteOnExit()} method.
+ * + * @param prefix prefix before the random number + * @param suffix file extension; include the '.' + * @param parentDir Directory to create the temporary file in-java.io.tmpdir
+ * used if not specificed
+ * @return a File reference to the new temporary file.
+ */
+ public static File createTempFile( String prefix, String suffix, File parentDir )
+ {
+ File result = null;
+ String parent = System.getProperty( "java.io.tmpdir" );
+ if ( parentDir != null )
+ {
+ parent = parentDir.getPath();
+ }
+ DecimalFormat fmt = new DecimalFormat( "#####" );
+ SecureRandom secureRandom = new SecureRandom();
+ long secureInitializer = secureRandom.nextLong();
+ Random rand = new Random( secureInitializer + Runtime.getRuntime().freeMemory() );
+ synchronized ( rand )
+ {
+ do
+ {
+ result = new File( parent, prefix + fmt.format( Math.abs( rand.nextInt() ) ) + suffix );
+ }
+ while ( result.exists() );
+ }
+
+ return result;
+ }
+
+ /**
+ * If wrappers is null or empty, the file will be copy only if to.lastModified() < from.lastModified()
+ * @param from the file to copy
+ * @param to the destination file
+ * @param encoding the file output encoding (only if wrappers is not empty)
+ * @param wrappers array of {@link FilterWrapper}
+ * @throws IOException if an IO error occurs during copying or filtering
+ */
+ public static void copyFile( File from, File to, String encoding, FilterWrapper[] wrappers )
+ throws IOException
+ {
+ copyFile( from, to, encoding, wrappers, false );
+ }
+
+ public static abstract class FilterWrapper
+ {
+ public abstract Reader getReader( Reader fileReader );
+ }
+
+ /**
+ * If wrappers is null or empty, the file will be copy only if to.lastModified() < from.lastModified() or if overwrite is true
+ * @param from the file to copy
+ * @param to the destination file
+ * @param encoding the file output encoding (only if wrappers is not empty)
+ * @param wrappers array of {@link FilterWrapper}
+ * @param overwrite if true and f wrappers is null or empty, the file will be copy
+ * enven if to.lastModified() < from.lastModified()
+ * @throws IOException if an IO error occurs during copying or filtering
+ * @since 1.5.2
+ */
+ public static void copyFile( File from, File to, String encoding, FilterWrapper[] wrappers, boolean overwrite )
+ throws IOException
+ {
+ if ( wrappers != null && wrappers.length > 0 )
+ {
+ // buffer so it isn't reading a byte at a time!
+ Reader fileReader = null;
+ Writer fileWriter = null;
+ try
+ {
+ if ( encoding == null || encoding.length() < 1 )
+ {
+ fileReader = new BufferedReader( new FileReader( from ) );
+ fileWriter = new FileWriter( to );
+ }
+ else
+ {
+ FileInputStream instream = new FileInputStream( from );
+
+ FileOutputStream outstream = new FileOutputStream( to );
+
+ fileReader = new BufferedReader( new InputStreamReader( instream, encoding ) );
+
+ fileWriter = new OutputStreamWriter( outstream, encoding );
+ }
+
+ Reader reader = fileReader;
+ for ( int i = 0; i < wrappers.length; i++ )
+ {
+ FilterWrapper wrapper = wrappers[i];
+ reader = wrapper.getReader( reader );
+ }
+
+ IOUtil.copy( reader, fileWriter );
+ }
+ finally
+ {
+ IOUtil.close( fileReader );
+ IOUtil.close( fileWriter );
+ }
+ }
+ else
+ {
+ if ( to.lastModified() < from.lastModified() || overwrite )
+ {
+ copyFile( from, to );
+ }
+ }
+ }
+
+ /**
+ * Note: the file content is read with platform encoding
+ *
+ * @param file the file
+ * @return a List containing every every line not starting with # and not empty
+ * @throws IOException if any
+ */
+ public static List loadFile( File file )
+ throws IOException
+ {
+ List lines = new ArrayList();
+
+ if ( file.exists() )
+ {
+ BufferedReader reader = new BufferedReader( new FileReader( file ) );
+
+ String line = reader.readLine();
+
+ while ( line != null )
+ {
+ line = line.trim();
+
+ if ( !line.startsWith( "#" ) && line.length() != 0 )
+ {
+ lines.add( line );
+ }
+ line = reader.readLine();
+ }
+
+ reader.close();
+ }
+
+ return lines;
+ }
+
+ /**
+ * For Windows OS, check if the file name contains any of the following characters:
+ * ":", "*", "?", "\"", "<", ">", "|"
+ *
+ * @param f not null file
+ * @return false
if the file path contains any of forbidden Windows characters,
+ * true
if the Os is not Windows or if the file path respect the Windows constraints.
+ * @see #INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME
+ * @since 1.5.2
+ */
+ public static boolean isValidWindowsFileName( File f )
+ {
+ if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
+ {
+ if ( StringUtils.indexOfAny( f.getName(), INVALID_CHARACTERS_FOR_WINDOWS_FILE_NAME ) != -1 )
+ {
+ return false;
+ }
+
+ if ( f.getParentFile()!= null)
+ {
+ return isValidWindowsFileName( f.getParentFile() );
+ }
+ }
+
+ return true;
+ }
+}
Propchange: geronimo/sandbox/djencks/osgi/framework/modules/geronimo-plugin/src/main/java/org/apache/geronimo/system/plugin/plexus/util/FileUtils.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/djencks/osgi/framework/modules/geronimo-plugin/src/main/java/org/apache/geronimo/system/plugin/plexus/util/FileUtils.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/djencks/osgi/framework/modules/geronimo-plugin/src/main/java/org/apache/geronimo/system/plugin/plexus/util/FileUtils.java
------------------------------------------------------------------------------
svn:mime-type = text/plain