You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by jv...@apache.org on 2006/04/18 15:59:34 UTC
svn commit: r394946 [2/4] - in
/maven/components/trunk/maven-core-it-verifier/src/main/java/org:
apache/maven/it/ codehaus/plexus/util/
Modified: maven/components/trunk/maven-core-it-verifier/src/main/java/org/codehaus/plexus/util/FileUtils.java
URL: http://svn.apache.org/viewcvs/maven/components/trunk/maven-core-it-verifier/src/main/java/org/codehaus/plexus/util/FileUtils.java?rev=394946&r1=394945&r2=394946&view=diff
==============================================================================
--- maven/components/trunk/maven-core-it-verifier/src/main/java/org/codehaus/plexus/util/FileUtils.java (original)
+++ maven/components/trunk/maven-core-it-verifier/src/main/java/org/codehaus/plexus/util/FileUtils.java Tue Apr 18 06:59:22 2006
@@ -56,10 +56,1091 @@
*/
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.URL;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Random;
+import java.util.Vector;
+
+/**
+ * This class provides basic facilities for manipulating files and file paths.
+ *
+ * <h3>Path-related methods</h3>
+ *
+ * <p>Methods exist to retrieve the components of a typical file path. For example
+ * <code>/www/hosted/mysite/index.html</code>, can be broken into:
+ * <ul>
+ * <li><code>/www/hosted/mysite/</code> -- retrievable through {@link #getPath}</li>
+ * <li><code>index.html</code> -- retrievable through {@link #removePath}</li>
+ * <li><code>/www/hosted/mysite/index</code> -- retrievable through {@link #removeExtension}</li>
+ * <li><code>html</code> -- retrievable through {@link #getExtension}</li>
+ * </ul>
+ * There are also methods to {@link #catPath concatenate two paths}, {@link #resolveFile resolve a
+ * path relative to a File} and {@link #normalize} a path.
+ * </p>
+ *
+ * <h3>File-related methods</h3>
+ * <p>
+ * There are methods to create a {@link #toFile File from a URL}, copy a
+ * {@link #copyFileToDirectory File to a directory},
+ * copy a {@link #copyFile File to another File},
+ * copy a {@link #copyURLToFile URL's contents to a File},
+ * as well as methods to {@link #deleteDirectory(File) delete} and {@link #cleanDirectory(File)
+ * clean} a directory.
+ * </p>
+ *
+ * Common {@link java.io.File} manipulation routines.
+ *
+ * Taken from the commons-utils repo.
+ * Also code from Alexandria's FileUtils.
+ * And from Avalon Excalibur's IO.
+ * And from Ant.
+ *
+ * @author <a href="mailto:burton@relativity.yi.org">Kevin A. Burton</A>
+ * @author <a href="mailto:sanders@codehaus.org">Scott Sanders</a>
+ * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
+ * @author <a href="mailto:Christoph.Reck@dlr.de">Christoph.Reck</a>
+ * @author <a href="mailto:peter@codehaus.org">Peter Donald</a>
+ * @author <a href="mailto:jefft@codehaus.org">Jeff Turner</a>
+ * @version $Id$
+ */
+public class FileUtils
+{
+ /**
+ * The number of bytes in a kilobyte.
+ */
+ public static final int ONE_KB = 1024;
+
+ /**
+ * The number of bytes in a megabyte.
+ */
+ public static final int ONE_MB = ONE_KB * ONE_KB;
+
+ /**
+ * The number of bytes in a gigabyte.
+ */
+ public static final int ONE_GB = ONE_KB * ONE_MB;
+
+ public static String[] getDefaultExcludes()
+ {
+ return DirectoryScanner.DEFAULTEXCLUDES;
+ }
+
+ public static List getDefaultExcludesAsList()
+ {
+ return Arrays.asList( getDefaultExcludes() );
+ }
+
+ /**
+ * 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.
+ * @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.
+ * @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.
+ * @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.
+ */
+ 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).
+ */
+ public static String extension( String filename )
+ {
+ int lastDot = filename.lastIndexOf( '.' );
+
+ if ( lastDot >= 0 )
+ {
+ return filename.substring( lastDot + 1 );
+ }
+ else
+ {
+ return "";
+ }
+ }
+
+ /**
+ * Check if a file exits.
+ *
+ * @param fileName The name of the file to check.
+ * @return true if file exists.
+ */
+ public static boolean fileExists( String fileName )
+ {
+ File file = new File( fileName );
+ return file.exists();
+ }
+
+ public static String fileRead( String file )
+ throws IOException
+ {
+ return fileRead( new File( file ) );
+ }
+
+ public static String fileRead( File file )
+ throws IOException
+ {
+ StringBuffer buf = new StringBuffer();
+
+ FileInputStream in = null;
+
+ try
+ {
+ in = new FileInputStream( file );
+ int count;
+ byte[] b = new byte[512];
+ while ( ( count = in.read( b ) ) > 0 ) // blocking read
+ {
+ buf.append( new String( b, 0, count ) );
+ }
+ }
+ finally
+ {
+ IOUtil.close( in );
+ }
+
+ return buf.toString();
+ }
+
+ /**
+ * Appends data to a file. The file will be created if it does not exist.
+ *
+ * @param fileName The name of the file to write.
+ * @param data The content to write to the file.
+ */
+ public static void fileAppend( String fileName, String data )
+ throws IOException
+ {
+ FileOutputStream out = null;
+ try
+ {
+ out = new FileOutputStream( fileName, true );
+ out.write( data.getBytes() );
+ }
+ finally
+ {
+ IOUtil.close( out );
+ }
+ }
+
+ /**
+ * Writes data to a file. The file will be created if it does not exist.
+ *
+ * @param fileName The name of the file to write.
+ * @param data The content to write to the file.
+ */
+ public static void fileWrite( String fileName, String data )
+ throws IOException
+ {
+ FileOutputStream out = null;
+ try
+ {
+ out = new FileOutputStream( fileName );
+ out.write( data.getBytes() );
+ }
+ finally
+ {
+ IOUtil.close( out );
+ }
+ }
+
+ /**
+ * Deletes a file.
+ *
+ * @param fileName The name 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 name 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 );
+ }
+
+ 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 )
+ {
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Creates a file handle.
+ *
+ * @param fileName The name of the file.
+ * @return A <code>File</code> 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"
+ */
+ public static String[] getFilesFromExtension( String directory, String[] extensions )
+ {
+
+ Vector files = new Vector();
+
+ java.io.File currentDir = new java.io.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];
+ java.io.File currentFile = new java.io.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 hepler 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
+ */
+ public static void mkdir( String dir )
+ {
+ File file = new File( dir );
+ 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
+ */
+ 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 <code>URL</code> to a <code>File</code>.
+ * @param url File URL.
+ * @return The equivalent <code>File</code> object, or <code>null</code> if the URL's protocol
+ * is not <code>file</code>
+ */
+ public static File toFile( final URL url )
+ {
+ if ( url.getProtocol().equals( "file" ) == false )
+ {
+ return null;
+ }
+ else
+ {
+ final String filename = url.getFile().replace( '/', File.separatorChar );
+ 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
+ * <pre>
+ * foo.txt --> foo
+ * a\b\c.jpg --> a\b\c
+ * a\b\c --> a\b\c
+ * </pre>
+ *
+ * @param filename the filename
+ * @return the filename minus extension
+ */
+ public static String removeExtension( final String filename )
+ {
+ final int index = filename.lastIndexOf( '.' );
+
+ if ( -1 == index )
+ {
+ return filename;
+ }
+ else
+ {
+ return filename.substring( 0, index );
+ }
+ }
+
+ /**
+ * Get extension from filename.
+ * ie
+ * <pre>
+ * foo.txt --> "txt"
+ * a\b\c.jpg --> "jpg"
+ * a\b\c --> ""
+ * </pre>
+ *
+ * @param filename the filename
+ * @return the extension of filename or "" if none
+ */
+ public static String getExtension( final String filename )
+ {
+ final int index = filename.lastIndexOf( '.' );
+
+ if ( -1 == index )
+ {
+ return "";
+ }
+ else
+ {
+ return filename.substring( index + 1 );
+ }
+ }
+
+ /**
+ * Remove path from filename. Equivalent to the unix command <code>basename</code>
+ * ie.
+ * <pre>
+ * a/b/c.txt --> c.txt
+ * a.txt --> a.txt
+ * </pre>
+ *
+ * @param filepath the filepath
+ * @return the filename minus path
+ */
+ public static String removePath( final String filepath )
+ {
+ return removePath( filepath, File.separatorChar );
+ }
+
+ /**
+ * Remove path from filename.
+ * ie.
+ * <pre>
+ * a/b/c.txt --> c.txt
+ * a.txt --> a.txt
+ * </pre>
+ *
+ * @param filepath the filepath
+ * @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;
+ }
+ else
+ {
+ return filepath.substring( index + 1 );
+ }
+ }
+
+ /**
+ * Get path from filename. Roughly equivalent to the unix command <code>dirname</code>.
+ * ie.
+ * <pre>
+ * a/b/c.txt --> a/b
+ * a.txt --> ""
+ * </pre>
+ *
+ * @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.
+ * <pre>
+ * a/b/c.txt --> a/b
+ * a.txt --> ""
+ * </pre>
+ *
+ * @param filepath the filepath
+ * @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 "";
+ }
+ else
+ {
+ return filepath.substring( 0, index );
+ }
+ }
+
+ /**
+ * Copy file from source to destination. If <code>destinationDirectory</code> does not exist, it
+ * (and any parent directories) will be created. If a file <code>source</code> in
+ * <code>destinationDirectory</code> exists, it will be overwritten.
+ *
+ * @param source An existing <code>File</code> to copy.
+ * @param destinationDirectory A directory to copy <code>source</code> into.
+ *
+ * @throws java.io.FileNotFoundException if <code>source</code> isn't a normal file.
+ * @throws IllegalArgumentException if <code>destinationDirectory</code> isn't a directory.
+ * @throws IOException if <code>source</code> does not exist, the file in
+ * <code>destinationDirectory</code> 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 <code>destinationDirectory</code> does not exist, it
+ * (and any parent directories) will be created. If a file <code>source</code> in
+ * <code>destinationDirectory</code> exists, it will be overwritten.
+ *
+ * @param source An existing <code>File</code> to copy.
+ * @param destinationDirectory A directory to copy <code>source</code> into.
+ *
+ * @throws java.io.FileNotFoundException if <code>source</code> isn't a normal file.
+ * @throws IllegalArgumentException if <code>destinationDirectory</code> isn't a directory.
+ * @throws IOException if <code>source</code> does not exist, the file in
+ * <code>destinationDirectory</code> 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 <code>destinationDirectory</code> does not exist, it
+ * (and any parent directories) will be created. If a file <code>source</code> in
+ * <code>destinationDirectory</code> exists, it will be overwritten.
+ *
+ * @param source An existing <code>File</code> to copy.
+ * @param destinationDirectory A directory to copy <code>source</code> into.
+ *
+ * @throws java.io.FileNotFoundException if <code>source</code> isn't a normal file.
+ * @throws IllegalArgumentException if <code>destinationDirectory</code> isn't a directory.
+ * @throws IOException if <code>source</code> does not exist, the file in
+ * <code>destinationDirectory</code> 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 <code>destinationDirectory</code> does not exist, it
+ * (and any parent directories) will be created. If a file <code>source</code> in
+ * <code>destinationDirectory</code> exists, it will be overwritten.
+ *
+ * @param source An existing <code>File</code> to copy.
+ * @param destinationDirectory A directory to copy <code>source</code> into.
+ *
+ * @throws java.io.FileNotFoundException if <code>source</code> isn't a normal file.
+ * @throws IllegalArgumentException if <code>destinationDirectory</code> isn't a directory.
+ * @throws IOException if <code>source</code> does not exist, the file in
+ * <code>destinationDirectory</code> 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 <code>destination</code> will be
+ * created if they don't already exist. <code>destination</code> will be overwritten if it
+ * already exists.
+ *
+ * @param source An existing non-directory <code>File</code> to copy bytes from.
+ * @param destination A non-directory <code>File</code> to write bytes to (possibly
+ * overwriting).
+ *
+ * @throws IOException if <code>source</code> does not exist, <code>destination</code> cannot be
+ * written to, or an IO error occurs during copying.
+ *
+ * @throws java.io.FileNotFoundException if <code>destination</code> 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 );
+ }
+
+ //does destinations directory exist ?
+ if ( destination.getParentFile() != null &&
+ !destination.getParentFile().exists() )
+ {
+ destination.getParentFile().mkdirs();
+ }
+
+ //make sure we can write to destination
+ if ( destination.exists() && !destination.canWrite() )
+ {
+ final String message = "Unable to open file " +
+ destination + " for writing.";
+ throw new IOException( message );
+ }
+
+ FileInputStream input = null;
+ FileOutputStream output = null;
+ try
+ {
+ input = new FileInputStream( source );
+ output = new FileOutputStream( destination );
+ IOUtil.copy( input, output );
+ }
+ finally
+ {
+ IOUtil.close( input );
+ IOUtil.close( output );
+ }
+
+ 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 <code>destination</code> will be created if they don't already exist.
+ * <code>destination</code> will be overwritten if it already exists.
+ *
+ * @param source An existing non-directory <code>File</code> to copy bytes from.
+ * @param destination A non-directory <code>File</code> to write bytes to (possibly
+ * overwriting).
+ *
+ * @throws IOException if <code>source</code> does not exist, <code>destination</code> cannot be
+ * written to, or an IO error occurs during copying.
+ *
+ * @throws java.io.FileNotFoundException if <code>destination</code> is a directory
+ * (use {@link #copyFileToDirectory}).
+ */
+ public static void copyFileIfModified( final File source, final File destination )
+ throws IOException
+ {
+ if ( destination.lastModified() < source.lastModified() )
+ {
+ copyFile( source, destination );
+ }
+ }
+ /**
+ * Copies bytes from the URL <code>source</code> to a file <code>destination</code>.
+ * The directories up to <code>destination</code> will be created if they don't already exist.
+ * <code>destination</code> will be overwritten if it already exists.
+ *
+ * @param source A <code>URL</code> to copy bytes from.
+ * @param destination A non-directory <code>File</code> to write bytes to (possibly
+ * overwriting).
+ *
+ * @throws IOException if
+ * <ul>
+ * <li><code>source</code> URL cannot be opened</li>
+ * <li><code>destination</code> cannot be written to</li>
+ * <li>an IO error occurs during copying</li>
+ * </ul>
+ */
+ public static void copyURLToFile( final URL source, final File destination )
+ throws IOException
+ {
+ //does destination directory exist ?
+ if ( destination.getParentFile() != null &&
+ !destination.getParentFile().exists() )
+ {
+ destination.getParentFile().mkdirs();
+ }
+
+ //make sure we can write to destination
+ if ( destination.exists() && !destination.canWrite() )
+ {
+ final String message = "Unable to open file " +
+ destination + " for writing.";
+ throw new IOException( message );
+ }
+
+ InputStream input = null;
+ FileOutputStream output = null;
+ try
+ {
+ input = source.openStream();
+ output = new FileOutputStream( destination );
+ IOUtil.copy( input, output );
+ }
+ finally
+ {
+ IOUtil.close( input );
+ IOUtil.close( output );
+ }
+ }
+
+ /**
+ * Normalize a path.
+ * Eliminates "/../" and "/./" in a string. Returns <code>null</code> if the ..'s went past the
+ * root.
+ * Eg:
+ * <pre>
+ * /foo// --> /foo/
+ * /foo/./ --> /foo/
+ * /foo/../bar --> /bar
+ * /foo/../bar/ --> /bar/
+ * /foo/../bar/../baz --> /baz
+ * //foo//./bar --> /foo/bar
+ * /../ --> null
+ * </pre>
+ *
+ * @param path the path to normalize
+ * @return the normalized String, or <code>null</code> 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 <code>..</code> will be
+ * properly handled.
+ * <p>Eg.,<br />
+ * <code>/a/b/c</code> + <code>d</code> = <code>/a/b/d</code><br />
+ * <code>/a/b/c</code> + <code>../d</code> = <code>/a/d</code><br />
+ * </p>
+ *
+ * Thieved from Tomcat sources...
+ *
+ * @return The concatenated paths, or null if error occurs
+ */
+ public static String catPath( final String lookupPath, final String path )
+ {
+ // Cut off the last slash and everything beyond
+ int index = lookupPath.lastIndexOf( "/" );
+ String lookup = lookupPath.substring( 0, index );
+ String pth = path;
+
+ // Deal with .. by chopping dirs off the lookup path
+ while ( pth.startsWith( "../" ) )
+ {
+ if ( lookup.length() > 0 )
+ {
+ index = lookup.lastIndexOf( "/" );
+ lookup = lookup.substring( 0, index );
+ }
+ else
+ {
+ // More ..'s than dirs, return null
+ return null;
+ }
+
+ index = pth.indexOf( "../" ) + 3;
+ pth = pth.substring( index );
+ }
+
+ return new StringBuffer( lookup ).append( "/" ).append( pth ).toString();
+ }
+
+ /**
+ * Resolve a file <code>filename</code> to it's canonical form. If <code>filename</code> is
+ * relative (doesn't start with <code>/</code>), it will be resolved relative to
+ * <code>baseFile</code>, otherwise it is treated as a normal root-relative path.
+ *
+ * @param baseFile Where to resolve <code>filename</code> from, if <code>filename</code> is
+ * relative.
+ * @param filename Absolute or relative file path to resolve.
+ * @return The canonical <code>File</code> of <code>filename</code>.
+ */
+ 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 ) )
+ {
+ File file = new File( filenm );
+
+ try
+ {
+ file = file.getCanonicalFile();
+ }
+ catch ( final IOException ioe )
+ {
+ }
+
+ 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 )
+ {
+ }
+
+ return file;
+ }
-public class FileUtils
-{
/**
* Delete a file. If file is directory delete it and all sub-directories.
*/
@@ -358,4 +1439,367 @@
return size;
}
-}
\ No newline at end of file
+
+ public static List getFiles( File directory, String includes, String excludes )
+ throws IOException
+ {
+ return getFiles( directory, includes, excludes, true );
+ }
+
+ 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;
+ }
+
+ public static String FS = System.getProperty( "file.separator" );
+
+ /**
+ * 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
+ {
+ 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();
+
+ String[] files = scanner.getIncludedFiles();
+
+ List list = new ArrayList();
+
+ for ( int i = 0; i < files.length; i++ )
+ {
+ if ( includeBasedir )
+ {
+ list.add( directory + FileUtils.FS + files[i] );
+ }
+ else
+ {
+ list.add( files[i] );
+ }
+ }
+
+ return list;
+ }
+
+ public static void copyDirectory( File sourceDirectory, File destinationDirectory )
+ throws IOException
+ {
+ copyDirectory( sourceDirectory, destinationDirectory, "**", null );
+ }
+
+ 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 structure.
+ *
+ * Note:
+ * <ul>
+ * <li>It will include empty directories.
+ * <li>The <code>sourceDirectory</code> must exists.
+ * </ul>
+ *
+ * @param sourceDirectory
+ * @param destinationDirectory
+ * @throws IOException
+ */
+ public static void copyDirectoryStructure( File sourceDirectory, File destinationDirectory )
+ throws IOException
+ {
+ if ( !sourceDirectory.exists() )
+ {
+ throw new IOException( "Source directory doesn't exists (" + sourceDirectory.getAbsolutePath() + ")." );
+ }
+
+ File[] files = sourceDirectory.listFiles();
+
+ String sourcePath = sourceDirectory.getAbsolutePath();
+
+ for ( int i = 0; i < files.length; i++ )
+ {
+ File file = files[i];
+
+ String dest = file.getAbsolutePath();
+
+ dest = dest.substring( sourcePath.length() + 1 );
+
+ File destination = new File( destinationDirectory, dest );
+
+ if ( file.isFile() )
+ {
+ destination = destination.getParentFile();
+
+ FileUtils.copyFileToDirectory( file, destination );
+ }
+ else if ( file.isDirectory() )
+ {
+ if ( !destination.exists() && !destination.mkdirs() )
+ {
+ throw new IOException( "Could not create destination directory '" + destination.getAbsolutePath() + "'." );
+ }
+
+ copyDirectoryStructure( file, destination );
+ }
+ else
+ {
+ throw new IOException( "Unknown file type: " + file.getAbsolutePath() );
+ }
+ }
+ }
+
+ /**
+ * Copies an entire directory structure but only source files with timestamp later than the destinations'.
+ *
+ * Note:
+ * <ul>
+ * <li>It will include empty directories.
+ * <li>The <code>sourceDirectory</code> must exists.
+ * </ul>
+ *
+ * @param sourceDirectory
+ * @param destinationDirectory
+ * @throws IOException
+ */
+ public static void copyDirectoryStructureIfModified( File sourceDirectory, File destinationDirectory )
+ throws IOException
+ {
+ if ( !sourceDirectory.exists() )
+ {
+ throw new IOException( "Source directory doesn't exists (" + sourceDirectory.getAbsolutePath() + ")." );
+ }
+
+ File[] files = sourceDirectory.listFiles();
+
+ String sourcePath = sourceDirectory.getAbsolutePath();
+
+ for ( int i = 0; i < files.length; i++ )
+ {
+ File file = files[i];
+
+ String dest = file.getAbsolutePath();
+
+ dest = dest.substring( sourcePath.length() + 1 );
+
+ File destination = new File( destinationDirectory, dest );
+
+ if ( file.isFile() )
+ {
+ destination = destination.getParentFile();
+
+ copyFileToDirectoryIfModified( file, destination );
+ }
+ else if ( file.isDirectory() )
+ {
+ if ( !destination.exists() && !destination.mkdirs() )
+ {
+ throw new IOException( "Could not create destination directory '" + destination.getAbsolutePath() + "'." );
+ }
+
+ copyDirectoryStructureIfModified( file, destination );
+ }
+ else
+ {
+ throw new IOException( "Unknown file type: " + file.getAbsolutePath() );
+ }
+ }
+ }
+
+ /**
+ * Renames a file, even if that involves crossing file system boundaries.
+ *
+ * <p>This will remove <code>to</code> (if it exists), ensure that
+ * <code>to</code>'s parent directory exists and move
+ * <code>from</code>, which involves deleting <code>from</code> as
+ * well.</p>
+ *
+ * @throws IOException if anything bad happens during this
+ * process. Note that <code>to</code> may have been deleted
+ * already when this happens.
+ *
+ * @param from the file to move
+ * @param to the new file name
+ */
+ 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.
+ *
+ * <p>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.</p>
+ * <p>
+ * The filename is prefixNNNNNsuffix where NNNN is a random number
+ * </p>
+ * <p>This method is different to File.createTempFile 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.</p>
+ *
+ * @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("#####");
+ Random rand = new Random(System.currentTimeMillis()
+ +Runtime.getRuntime().freeMemory());
+ synchronized (rand) {
+ do {
+ result = new File(parent,
+ prefix + fmt.format(Math.abs(rand.nextInt()))
+ + suffix);
+ } while (result.exists());
+ }
+ return result;
+ }
+
+ public static void copyFile(File from, File to, String encoding, FilterWrapper[] wrappers)
+ 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() )
+ {
+ copyFile( from, to );
+ }
+ }
+ }
+
+ public static abstract class FilterWrapper {
+ public abstract Reader getReader(Reader fileReader);
+ }
+}
Added: maven/components/trunk/maven-core-it-verifier/src/main/java/org/codehaus/plexus/util/IOUtil.java
URL: http://svn.apache.org/viewcvs/maven/components/trunk/maven-core-it-verifier/src/main/java/org/codehaus/plexus/util/IOUtil.java?rev=394946&view=auto
==============================================================================
--- maven/components/trunk/maven-core-it-verifier/src/main/java/org/codehaus/plexus/util/IOUtil.java (added)
+++ maven/components/trunk/maven-core-it-verifier/src/main/java/org/codehaus/plexus/util/IOUtil.java Tue Apr 18 06:59:22 2006
@@ -0,0 +1,813 @@
+package org.codehaus.plexus.util;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.codehaus.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache Turbine" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact codehaus@codehaus.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache Turbine", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.codehaus.org/>.
+ */
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+
+/**
+ * General IO Stream manipulation.
+ * <p>
+ * This class provides static utility methods for input/output operations, particularly buffered
+ * copying between sources (<code>InputStream</code>, <code>Reader</code>, <code>String</code> and
+ * <code>byte[]</code>) and destinations (<code>OutputStream</code>, <code>Writer</code>,
+ * <code>String</code> and <code>byte[]</code>).
+ * </p>
+ *
+ * <p>Unless otherwise noted, these <code>copy</code> methods do <em>not</em> flush or close the
+ * streams. Often, doing so would require making non-portable assumptions about the streams' origin
+ * and further use. This means that both streams' <code>close()</code> methods must be called after
+ * copying. if one omits this step, then the stream resources (sockets, file descriptors) are
+ * released when the associated Stream is garbage-collected. It is not a good idea to rely on this
+ * mechanism. For a good overview of the distinction between "memory management" and "resource
+ * management", see <a href="http://www.unixreview.com/articles/1998/9804/9804ja/ja.htm">this
+ * UnixReview article</a></p>
+ *
+ * <p>For each <code>copy</code> method, a variant is provided that allows the caller to specify the
+ * buffer size (the default is 4k). As the buffer size can have a fairly large impact on speed, this
+ * may be worth tweaking. Often "large buffer -> faster" does not hold, even for large data
+ * transfers.</p>
+ *
+ * <p>For byte-to-char methods, a <code>copy</code> variant allows the encoding to be selected
+ * (otherwise the platform default is used).</p>
+ *
+ * <p>The <code>copy</code> methods use an internal buffer when copying. It is therefore advisable
+ * <em>not</em> to deliberately wrap the stream arguments to the <code>copy</code> methods in
+ * <code>Buffered*</code> streams. For example, don't do the
+ * following:</p>
+ *
+ * <code>copy( new BufferedInputStream( in ), new BufferedOutputStream( out ) );</code>
+ *
+ * <p>The rationale is as follows:</p>
+ *
+ * <p>Imagine that an InputStream's read() is a very expensive operation, which would usually suggest
+ * wrapping in a BufferedInputStream. The BufferedInputStream works by issuing infrequent
+ * {@link java.io.InputStream#read(byte[] b, int off, int len)} requests on the underlying InputStream, to
+ * fill an internal buffer, from which further <code>read</code> requests can inexpensively get
+ * their data (until the buffer runs out).</p>
+ * <p>However, the <code>copy</code> methods do the same thing, keeping an internal buffer,
+ * populated by {@link InputStream#read(byte[] b, int off, int len)} requests. Having two buffers
+ * (or three if the destination stream is also buffered) is pointless, and the unnecessary buffer
+ * management hurts performance slightly (about 3%, according to some simple experiments).</p>
+ *
+ * @author <a href="mailto:peter@codehaus.org">Peter Donald</a>
+ * @author <a href="mailto:jefft@codehaus.org">Jeff Turner</a>
+ * @version CVS $Revision: 1106 $ $Date$
+ * @since 4.0
+ */
+
+/*
+ * Behold, intrepid explorers; a map of this class:
+ *
+ * Method Input Output Dependency
+ * ------ ----- ------ -------
+ * 1 copy InputStream OutputStream (primitive)
+ * 2 copy Reader Writer (primitive)
+ *
+ * 3 copy InputStream Writer 2
+ * 4 toString InputStream String 3
+ * 5 toByteArray InputStream byte[] 1
+ *
+ * 6 copy Reader OutputStream 2
+ * 7 toString Reader String 2
+ * 8 toByteArray Reader byte[] 6
+ *
+ * 9 copy String OutputStream 2
+ * 10 copy String Writer (trivial)
+ * 11 toByteArray String byte[] 9
+ *
+ * 12 copy byte[] Writer 3
+ * 13 toString byte[] String 12
+ * 14 copy byte[] OutputStream (trivial)
+ *
+ *
+ * Note that only the first two methods shuffle bytes; the rest use these two, or (if possible) copy
+ * using native Java copy methods. As there are method variants to specify buffer size and encoding,
+ * each row may correspond to up to 4 methods.
+ *
+ */
+
+public final class IOUtil
+{
+ private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+
+ /**
+ * Private constructor to prevent instantiation.
+ */
+ private IOUtil()
+ {
+ }
+
+ ///////////////////////////////////////////////////////////////
+ // Core copy methods
+ ///////////////////////////////////////////////////////////////
+
+ /**
+ * Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
+ */
+ public static void copy( final InputStream input, final OutputStream output )
+ throws IOException
+ {
+ copy( input, output, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
+ * @param bufferSize Size of internal buffer to use.
+ */
+ public static void copy( final InputStream input,
+ final OutputStream output,
+ final int bufferSize )
+ throws IOException
+ {
+ final byte[] buffer = new byte[bufferSize];
+ int n = 0;
+ while ( -1 != ( n = input.read( buffer ) ) )
+ {
+ output.write( buffer, 0, n );
+ }
+ }
+
+ /**
+ * Copy chars from a <code>Reader</code> to a <code>Writer</code>.
+ */
+ public static void copy( final Reader input, final Writer output )
+ throws IOException
+ {
+ copy( input, output, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Copy chars from a <code>Reader</code> to a <code>Writer</code>.
+ * @param bufferSize Size of internal buffer to use.
+ */
+ public static void copy( final Reader input, final Writer output, final int bufferSize )
+ throws IOException
+ {
+ final char[] buffer = new char[bufferSize];
+ int n = 0;
+ while ( -1 != ( n = input.read( buffer ) ) )
+ {
+ output.write( buffer, 0, n );
+ }
+ output.flush();
+ }
+
+ ///////////////////////////////////////////////////////////////
+ // Derived copy methods
+ // InputStream -> *
+ ///////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////
+ // InputStream -> Writer
+
+ /**
+ * Copy and convert bytes from an <code>InputStream</code> to chars on a
+ * <code>Writer</code>.
+ * The platform's default encoding is used for the byte-to-char conversion.
+ */
+ public static void copy( final InputStream input, final Writer output )
+ throws IOException
+ {
+ copy( input, output, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Copy and convert bytes from an <code>InputStream</code> to chars on a
+ * <code>Writer</code>.
+ * The platform's default encoding is used for the byte-to-char conversion.
+ * @param bufferSize Size of internal buffer to use.
+ */
+ public static void copy( final InputStream input, final Writer output, final int bufferSize )
+ throws IOException
+ {
+ final InputStreamReader in = new InputStreamReader( input );
+ copy( in, output, bufferSize );
+ }
+
+ /**
+ * Copy and convert bytes from an <code>InputStream</code> to chars on a
+ * <code>Writer</code>, using the specified encoding.
+ * @param encoding The name of a supported character encoding. See the
+ * <a href="http://www.iana.org/assignments/character-sets">IANA
+ * Charset Registry</a> for a list of valid encoding types.
+ */
+ public static void copy( final InputStream input, final Writer output, final String encoding )
+ throws IOException
+ {
+ final InputStreamReader in = new InputStreamReader( input, encoding );
+ copy( in, output );
+ }
+
+ /**
+ * Copy and convert bytes from an <code>InputStream</code> to chars on a
+ * <code>Writer</code>, using the specified encoding.
+ * @param encoding The name of a supported character encoding. See the
+ * <a href="http://www.iana.org/assignments/character-sets">IANA
+ * Charset Registry</a> for a list of valid encoding types.
+ * @param bufferSize Size of internal buffer to use.
+ */
+ public static void copy( final InputStream input,
+ final Writer output,
+ final String encoding,
+ final int bufferSize )
+ throws IOException
+ {
+ final InputStreamReader in = new InputStreamReader( input, encoding );
+ copy( in, output, bufferSize );
+ }
+
+
+ ///////////////////////////////////////////////////////////////
+ // InputStream -> String
+
+ /**
+ * Get the contents of an <code>InputStream</code> as a String.
+ * The platform's default encoding is used for the byte-to-char conversion.
+ */
+ public static String toString( final InputStream input )
+ throws IOException
+ {
+ return toString( input, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Get the contents of an <code>InputStream</code> as a String.
+ * The platform's default encoding is used for the byte-to-char conversion.
+ * @param bufferSize Size of internal buffer to use.
+ */
+ public static String toString( final InputStream input, final int bufferSize )
+ throws IOException
+ {
+ final StringWriter sw = new StringWriter();
+ copy( input, sw, bufferSize );
+ return sw.toString();
+ }
+
+ /**
+ * Get the contents of an <code>InputStream</code> as a String.
+ * @param encoding The name of a supported character encoding. See the
+ * <a href="http://www.iana.org/assignments/character-sets">IANA
+ * Charset Registry</a> for a list of valid encoding types.
+ */
+ public static String toString( final InputStream input, final String encoding )
+ throws IOException
+ {
+ return toString( input, encoding, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Get the contents of an <code>InputStream</code> as a String.
+ * @param encoding The name of a supported character encoding. See the
+ * <a href="http://www.iana.org/assignments/character-sets">IANA
+ * Charset Registry</a> for a list of valid encoding types.
+ * @param bufferSize Size of internal buffer to use.
+ */
+ public static String toString( final InputStream input,
+ final String encoding,
+ final int bufferSize )
+ throws IOException
+ {
+ final StringWriter sw = new StringWriter();
+ copy( input, sw, encoding, bufferSize );
+ return sw.toString();
+ }
+
+ ///////////////////////////////////////////////////////////////
+ // InputStream -> byte[]
+
+ /**
+ * Get the contents of an <code>InputStream</code> as a <code>byte[]</code>.
+ */
+ public static byte[] toByteArray( final InputStream input )
+ throws IOException
+ {
+ return toByteArray( input, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Get the contents of an <code>InputStream</code> as a <code>byte[]</code>.
+ * @param bufferSize Size of internal buffer to use.
+ */
+ public static byte[] toByteArray( final InputStream input, final int bufferSize )
+ throws IOException
+ {
+ final ByteArrayOutputStream output = new ByteArrayOutputStream();
+ copy( input, output, bufferSize );
+ return output.toByteArray();
+ }
+
+
+ ///////////////////////////////////////////////////////////////
+ // Derived copy methods
+ // Reader -> *
+ ///////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////
+ // Reader -> OutputStream
+ /**
+ * Serialize chars from a <code>Reader</code> to bytes on an <code>OutputStream</code>, and
+ * flush the <code>OutputStream</code>.
+ */
+ public static void copy( final Reader input, final OutputStream output )
+ throws IOException
+ {
+ copy( input, output, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Serialize chars from a <code>Reader</code> to bytes on an <code>OutputStream</code>, and
+ * flush the <code>OutputStream</code>.
+ * @param bufferSize Size of internal buffer to use.
+ */
+ public static void copy( final Reader input, final OutputStream output, final int bufferSize )
+ throws IOException
+ {
+ final OutputStreamWriter out = new OutputStreamWriter( output );
+ copy( input, out, bufferSize );
+ // NOTE: Unless anyone is planning on rewriting OutputStreamWriter, we have to flush
+ // here.
+ out.flush();
+ }
+
+ ///////////////////////////////////////////////////////////////
+ // Reader -> String
+ /**
+ * Get the contents of a <code>Reader</code> as a String.
+ */
+ public static String toString( final Reader input )
+ throws IOException
+ {
+ return toString( input, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Get the contents of a <code>Reader</code> as a String.
+ * @param bufferSize Size of internal buffer to use.
+ */
+ public static String toString( final Reader input, final int bufferSize )
+ throws IOException
+ {
+ final StringWriter sw = new StringWriter();
+ copy( input, sw, bufferSize );
+ return sw.toString();
+ }
+
+
+ ///////////////////////////////////////////////////////////////
+ // Reader -> byte[]
+ /**
+ * Get the contents of a <code>Reader</code> as a <code>byte[]</code>.
+ */
+ public static byte[] toByteArray( final Reader input )
+ throws IOException
+ {
+ return toByteArray( input, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Get the contents of a <code>Reader</code> as a <code>byte[]</code>.
+ * @param bufferSize Size of internal buffer to use.
+ */
+ public static byte[] toByteArray( final Reader input, final int bufferSize )
+ throws IOException
+ {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ copy( input, output, bufferSize );
+ return output.toByteArray();
+ }
+
+
+ ///////////////////////////////////////////////////////////////
+ // Derived copy methods
+ // String -> *
+ ///////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////
+ // String -> OutputStream
+
+ /**
+ * Serialize chars from a <code>String</code> to bytes on an <code>OutputStream</code>, and
+ * flush the <code>OutputStream</code>.
+ */
+ public static void copy( final String input, final OutputStream output )
+ throws IOException
+ {
+ copy( input, output, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Serialize chars from a <code>String</code> to bytes on an <code>OutputStream</code>, and
+ * flush the <code>OutputStream</code>.
+ * @param bufferSize Size of internal buffer to use.
+ */
+ public static void copy( final String input, final OutputStream output, final int bufferSize )
+ throws IOException
+ {
+ final StringReader in = new StringReader( input );
+ final OutputStreamWriter out = new OutputStreamWriter( output );
+ copy( in, out, bufferSize );
+ // NOTE: Unless anyone is planning on rewriting OutputStreamWriter, we have to flush
+ // here.
+ out.flush();
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////
+ // String -> Writer
+
+ /**
+ * Copy chars from a <code>String</code> to a <code>Writer</code>.
+ */
+ public static void copy( final String input, final Writer output )
+ throws IOException
+ {
+ output.write( input );
+ }
+
+ /**
+ * Copy bytes from an <code>InputStream</code> to an
+ * <code>OutputStream</code>, with buffering.
+ * This is equivalent to passing a
+ * {@link java.io.BufferedInputStream} and
+ * {@link java.io.BufferedOutputStream} to {@link #copy(InputStream, OutputStream)},
+ * and flushing the output stream afterwards. The streams are not closed
+ * after the copy.
+ * @deprecated Buffering streams is actively harmful! See the class description as to why. Use
+ * {@link #copy(InputStream, OutputStream)} instead.
+ */
+ public static void bufferedCopy( final InputStream input, final OutputStream output )
+ throws IOException
+ {
+ final BufferedInputStream in = new BufferedInputStream( input );
+ final BufferedOutputStream out = new BufferedOutputStream( output );
+ copy( in, out );
+ out.flush();
+ }
+
+
+ ///////////////////////////////////////////////////////////////
+ // String -> byte[]
+ /**
+ * Get the contents of a <code>String</code> as a <code>byte[]</code>.
+ */
+ public static byte[] toByteArray( final String input )
+ throws IOException
+ {
+ return toByteArray( input, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Get the contents of a <code>String</code> as a <code>byte[]</code>.
+ * @param bufferSize Size of internal buffer to use.
+ */
+ public static byte[] toByteArray( final String input, final int bufferSize )
+ throws IOException
+ {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ copy( input, output, bufferSize );
+ return output.toByteArray();
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////
+ // Derived copy methods
+ // byte[] -> *
+ ///////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////
+ // byte[] -> Writer
+
+ /**
+ * Copy and convert bytes from a <code>byte[]</code> to chars on a
+ * <code>Writer</code>.
+ * The platform's default encoding is used for the byte-to-char conversion.
+ */
+ public static void copy( final byte[] input, final Writer output )
+ throws IOException
+ {
+ copy( input, output, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Copy and convert bytes from a <code>byte[]</code> to chars on a
+ * <code>Writer</code>.
+ * The platform's default encoding is used for the byte-to-char conversion.
+ * @param bufferSize Size of internal buffer to use.
+ */
+ public static void copy( final byte[] input, final Writer output, final int bufferSize )
+ throws IOException
+ {
+ final ByteArrayInputStream in = new ByteArrayInputStream( input );
+ copy( in, output, bufferSize );
+ }
+
+ /**
+ * Copy and convert bytes from a <code>byte[]</code> to chars on a
+ * <code>Writer</code>, using the specified encoding.
+ * @param encoding The name of a supported character encoding. See the
+ * <a href="http://www.iana.org/assignments/character-sets">IANA
+ * Charset Registry</a> for a list of valid encoding types.
+ */
+ public static void copy( final byte[] input, final Writer output, final String encoding )
+ throws IOException
+ {
+ final ByteArrayInputStream in = new ByteArrayInputStream( input );
+ copy( in, output, encoding );
+ }
+
+ /**
+ * Copy and convert bytes from a <code>byte[]</code> to chars on a
+ * <code>Writer</code>, using the specified encoding.
+ * @param encoding The name of a supported character encoding. See the
+ * <a href="http://www.iana.org/assignments/character-sets">IANA
+ * Charset Registry</a> for a list of valid encoding types.
+ * @param bufferSize Size of internal buffer to use.
+ */
+ public static void copy( final byte[] input,
+ final Writer output,
+ final String encoding,
+ final int bufferSize )
+ throws IOException
+ {
+ final ByteArrayInputStream in = new ByteArrayInputStream( input );
+ copy( in, output, encoding, bufferSize );
+ }
+
+
+ ///////////////////////////////////////////////////////////////
+ // byte[] -> String
+
+ /**
+ * Get the contents of a <code>byte[]</code> as a String.
+ * The platform's default encoding is used for the byte-to-char conversion.
+ */
+ public static String toString( final byte[] input )
+ throws IOException
+ {
+ return toString( input, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Get the contents of a <code>byte[]</code> as a String.
+ * The platform's default encoding is used for the byte-to-char conversion.
+ * @param bufferSize Size of internal buffer to use.
+ */
+ public static String toString( final byte[] input, final int bufferSize )
+ throws IOException
+ {
+ final StringWriter sw = new StringWriter();
+ copy( input, sw, bufferSize );
+ return sw.toString();
+ }
+
+ /**
+ * Get the contents of a <code>byte[]</code> as a String.
+ * @param encoding The name of a supported character encoding. See the
+ * <a href="http://www.iana.org/assignments/character-sets">IANA
+ * Charset Registry</a> for a list of valid encoding types.
+ */
+ public static String toString( final byte[] input, final String encoding )
+ throws IOException
+ {
+ return toString( input, encoding, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Get the contents of a <code>byte[]</code> as a String.
+ * @param encoding The name of a supported character encoding. See the
+ * <a href="http://www.iana.org/assignments/character-sets">IANA
+ * Charset Registry</a> for a list of valid encoding types.
+ * @param bufferSize Size of internal buffer to use.
+ */
+ public static String toString( final byte[] input,
+ final String encoding,
+ final int bufferSize )
+ throws IOException
+ {
+ final StringWriter sw = new StringWriter();
+ copy( input, sw, encoding, bufferSize );
+ return sw.toString();
+ }
+
+
+ ///////////////////////////////////////////////////////////////
+ // byte[] -> OutputStream
+
+ /**
+ * Copy bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
+ */
+ public static void copy( final byte[] input, final OutputStream output )
+ throws IOException
+ {
+ copy( input, output, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Copy bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
+ * @param bufferSize Size of internal buffer to use.
+ */
+ public static void copy( final byte[] input,
+ final OutputStream output,
+ final int bufferSize )
+ throws IOException
+ {
+ output.write( input );
+ }
+
+ /**
+ * Compare the contents of two Streams to determine if they are equal or not.
+ *
+ * @param input1 the first stream
+ * @param input2 the second stream
+ * @return true if the content of the streams are equal or they both don't exist, false otherwise
+ */
+ public static boolean contentEquals( final InputStream input1,
+ final InputStream input2 )
+ throws IOException
+ {
+ final InputStream bufferedInput1 = new BufferedInputStream( input1 );
+ final InputStream bufferedInput2 = new BufferedInputStream( input2 );
+
+ int ch = bufferedInput1.read();
+ while ( -1 != ch )
+ {
+ final int ch2 = bufferedInput2.read();
+ if ( ch != ch2 )
+ {
+ return false;
+ }
+ ch = bufferedInput1.read();
+ }
+
+ final int ch2 = bufferedInput2.read();
+ if ( -1 != ch2 )
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ // closeXXX()
+ // ----------------------------------------------------------------------
+
+ /**
+ * Closes the input stream. The input stream can be null and any IOException's will be swallowed.
+ *
+ * @param inputStream The stream to close.
+ */
+ public static void close( InputStream inputStream )
+ {
+ if ( inputStream == null )
+ {
+ return;
+ }
+
+ try
+ {
+ inputStream.close();
+ }
+ catch( IOException ex )
+ {
+ // ignore
+ }
+ }
+
+ /**
+ * Closes the output stream. The output stream can be null and any IOException's will be swallowed.
+ *
+ * @param outputStream The stream to close.
+ */
+ public static void close( OutputStream outputStream )
+ {
+ if ( outputStream == null )
+ {
+ return;
+ }
+
+ try
+ {
+ outputStream.close();
+ }
+ catch( IOException ex )
+ {
+ // ignore
+ }
+ }
+
+ /**
+ * Closes the reader. The reader can be null and any IOException's will be swallowed.
+ *
+ * @param reader The reader to close.
+ */
+ public static void close( Reader reader )
+ {
+ if ( reader == null )
+ {
+ return;
+ }
+
+ try
+ {
+ reader.close();
+ }
+ catch( IOException ex )
+ {
+ // ignore
+ }
+ }
+
+ /**
+ * Closes the writer. The writer can be null and any IOException's will be swallowed.
+ *
+ * @param wrtier The writer to close.
+ */
+ public static void close( Writer writer )
+ {
+ if ( writer == null )
+ {
+ return;
+ }
+
+ try
+ {
+ writer.close();
+ }
+ catch( IOException ex )
+ {
+ // ignore
+ }
+ }
+}
Propchange: maven/components/trunk/maven-core-it-verifier/src/main/java/org/codehaus/plexus/util/IOUtil.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: maven/components/trunk/maven-core-it-verifier/src/main/java/org/codehaus/plexus/util/IOUtil.java
------------------------------------------------------------------------------
svn:keywords = "Author Date Id Revision"