bb.io
Class FileUtil

java.lang.Object
  extended by bb.io.FileUtil

public final class FileUtil
extends Object

Provides static utility methods for dealing with normal Files.

This class is multithread safe: it is stateless.

This class checks for thread interruption only before major blocking operations in order to achieve a reasonable balance between cancellation responsiveness and program performance (see Doug Lea Concurrent Programming in Java Second Edition p. 170).

Author:
Brent Boyer
See Also:
DirUtil

Nested Class Summary
static class FileUtil.UnitTest
          See the Overview page of the project's javadocs for a general description of this unit test class.
 
Constructor Summary
private FileUtil()
          This sole private constructor suppresses the default (public) constructor, ensuring non-instantiability outside of this class.
 
Method Summary
private static int calcBufferSize(File file1, File file2)
           
private static boolean canEncode(char c)
          Determines whether or not this platform's default Charset) can encode c and then decode it back to the exact same value.
static File changeExtension(File file, String extensionNew)
          Trys to change file's extension to extensionNew.
static long compareContents(File file1, File file2)
          Compares the contents of the two supplied normal files, byte by byte.
static void copy(File source, File target, boolean append)
          Copies source to target.
static File createTemp(File file)
          Creates a temporary normal file.
static File createTemp(String path)
          Returns createTemp( new File(path) ).
static File createTempLog(String childPath)
          Creates a temp file inside the log directory.
static void delete(File file)
          Trys to delete file, and throws an IOException if the delete failed.
static void deleteIfExists(File file)
          Calls delete(file) if file !
private static int findWhereDiffer(byte[] bytes1, byte[] bytes2, int limit)
           
static String getExtension(File file)
          Returns the file's extension, defined here as the part of its name after the last '.' char.
static String getExtension(File file, boolean useFirstPeriod, boolean includePeriod)
          Returns the file's extension.
static String getNameMinusExtension(File file)
          Returns the file's name minus any extension, that is, the part of its name up to (but not including) the last '.' char.
static String getParentRelativeTo(File fileChild, File fileRoot)
          Returns a String that represents that part of fileChild's parent directory path which is contained inside fileRoot (that is, fileChild's parent's path relative to fileRoot).
static String getPathRelativeTo(File fileChild, File fileRoot)
          Returns that portion of the path of fileChild which is relative to the path of fileRoot.
static File getRoot(File file)
          Returns the filesystem root for file.
static File move(File file, File directory)
          Moves file into directory.
static char[] readAsciiToChars(File file)
          Reads file's contents into a byte[] (using the readBytes method), converts that into a char[] (using the StringUtil.asciiBytesToChars method) returns the char[].
static byte[] readBytes(File file)
          Reads file's contents into a byte[] which is returned.
static byte[] readBytesEnd(File file, int n)
          Reads the final part of file's contents into a byte[] which is returned.
static char[] readChars(File file)
          Reads file's contents into a byte[] (using readBytes), converts that into a char[] (using StringUtil.bytesToChars), and then returns the char[].
static String readString(File file)
          Returns new String( readBytes(file) ).
static File rename(File file1, File file2)
          Trys to rename file1 to file2.
static void writeBytes(byte[] bytes, File file, boolean append)
          Writes bytes into file.
static void writeString(String string, File file, boolean append)
          Simply executes writeBytes( string.getBytes(), file, append ).
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

FileUtil

private FileUtil()
This sole private constructor suppresses the default (public) constructor, ensuring non-instantiability outside of this class.

Method Detail

getNameMinusExtension

public static String getNameMinusExtension(File file)
                                    throws IllegalArgumentException
Returns the file's name minus any extension, that is, the part of its name up to (but not including) the last '.' char. For example, if presented with a file named "helloWorld.old.txt" then "helloWorld.old" is returned. If no extension exists (either because there is nothing after the last '.' char or a '.' char never occurs) then the complete file name (up to but not including any final '.' char) is returned. Note that the File need not actually exist nor be a normal file.

Parameters:
file - the File whose name is will be returned
Throws:
IllegalArgumentException - if file == null

getExtension

public static String getExtension(File file)
                           throws IllegalArgumentException
Returns the file's extension, defined here as the part of its name after the last '.' char.

This is a convenience method which simply returns getExtension(file, false, false). So, all the rules discussed for that method apply here. For example, if presented with a file named "helloWorld.old.txt" then "txt" is returned. If no extension exists (either because there is nothing after the last '.' char or a '.' char never occurs) then the blank string "" is returned. Note that the File need not actually exist nor be a normal file.

Parameters:
file - the File whose extension will be returned
Throws:
IllegalArgumentException - if file is null

getExtension

public static String getExtension(File file,
                                  boolean useFirstPeriod,
                                  boolean includePeriod)
                           throws IllegalArgumentException
Returns the file's extension.

If useFirstPeriod is true, then the extension starts at the first occurence of a period (i.e. '.' char) in file's name, otherwise the extension starts at the last occurence of a period in file's name. If includePeriod is true, then the period is included in the result, otherwise it is excluded. For example, if presented with a file named "helloWorld.old.txt", then the following table shows what is returned for the various combinations of useFirstPeriod and includePeriod:

includePeriod
true false
useFirstPeriod true .old.txt old.txt
false .txt txt

If no extension exists (i.e. there is no '.' char) then the blank string "" is returned. Note that the File need not actually exist nor be a normal file.

Parameters:
file - the File whose extension will be returned
useFirstPeriod - if true then the extension starts at the first occurence of a period (i.e. '.' char) in file's name, otherwise the extension starts at the last occurence of a period in file's name
includePeriod - if true, then the period is included in the result, otherwise it is excluded
Throws:
IllegalArgumentException - if file is null

changeExtension

public static File changeExtension(File file,
                                   String extensionNew)
                            throws IllegalArgumentException,
                                   SecurityException,
                                   IOException
Trys to change file's extension to extensionNew. If file currently has an extension, it is replaced by extensionNew, and if file lacks an extension, extensionNew is appended to its name. The new file must not currently exist (to be safest, this method never overwrites).

Parameters:
file - the currently existing file
extensionNew - the new extension for file; must not contain a '.' char in it
Returns:
a new File instance that has extensionNew
Throws:
IllegalArgumentException - if file is not valid; extensionNew is blank or contains a '.' char
SecurityException - if a security manager exists and write access to file
IOException - if an I/O problem occurs; this includes failure of the file to be renamed

getRoot

public static File getRoot(File file)
                    throws IllegalArgumentException,
                           SecurityException,
                           IOException
Returns the filesystem root for file. Specifically, this method traces back parent Files until there are no more, and returns the last one found.

Note: unlike almost all other methods in this class, file need not be a normal file; it could be a directory as well. Corollary: the result is file itself if file is a filesystem root.

Throws:
IllegalArgumentException - if file is null, or non-existent
SecurityException - if a security manager exists and denies read access to file
IOException - if an I/O problem occurs

getPathRelativeTo

public static String getPathRelativeTo(File fileChild,
                                       File fileRoot)
                                throws IllegalArgumentException
Returns that portion of the path of fileChild which is relative to the path of fileRoot. For example, if fileChild.getPath() = "/dirA/dirB/dirC/file1" and fileRoot.getPath() = "/dirA/dirB" then the result is "dirC/file1". Note that the result never begins with a path separator char. Neither File need actually exist; this method simply does String operations on their paths. If fileChild equals fileRoot, then a blank String is returned.

Throws:
IllegalArgumentException - if fileChild is null; fileRoot is null; fileChild is not contained under fileRoot

getParentRelativeTo

public static String getParentRelativeTo(File fileChild,
                                         File fileRoot)
                                  throws IllegalArgumentException
Returns a String that represents that part of fileChild's parent directory path which is contained inside fileRoot (that is, fileChild's parent's path relative to fileRoot). For example, if fileChild.getPath() = "/dirA/dirB/dirC/file1" and fileRoot.getPath() = "/dirA/dirB" then the result is "dirC". Note that the result never begins with a path separator char. Neither File need actually exist; this method simply does String operations on their paths.

Throws:
IllegalArgumentException - if file == null; if root == null; file has no parent; if root does not contain file's parent

createTemp

public static File createTemp(String path)
                       throws IllegalArgumentException,
                              SecurityException,
                              RuntimeException
Returns createTemp( new File(path) ).

Returns:
a new File constructed from path
Throws:
IllegalArgumentException - if path == null
SecurityException - if a security manager exists and denies read access to the file
RuntimeException - (or some subclass) if any other error occurs; this may merely wrap some other underlying Throwable

createTemp

public static File createTemp(File file)
                       throws IllegalArgumentException,
                              SecurityException,
                              RuntimeException
Creates a temporary normal file.

Does the following actions:

  1. attempts to delete file if it currently exists
  2. attempts to create a new empty version of file (Warning: does not create any parent directories that do not currently exist, because those directories cannot be automatically deleted upon exit. Therefore, this method fails if the parent directories do not all exist.)
  3. calls deleteOnExit on file, ensuring that file is temporary
Note that unlike File.createTempFile, which adds random numbers inside the file names that it creates, this method does no filename change, which allows you to work with files of a known name. Furthermore, this method catches all checked Exceptions and converts them to a RuntimeException before rethrowing them, so it may be used to assign fields.

Returns:
the supplied file arg
Throws:
IllegalArgumentException - if file == null
SecurityException - if a security manager exists and denies read access to the file
RuntimeException - (or some subclass) if any other error occurs; this may merely wrap some other underlying Throwable
See Also:
Bugs in temp file deletion

createTempLog

public static File createTempLog(String childPath)
                          throws IllegalArgumentException,
                                 SecurityException,
                                 RuntimeException
Creates a temp file inside the log directory.

This method behaves as if it returns createTemp( LogUtil.makeLogFile(childPath) ). However, it is implemented slightly differently: it first ensures that the parent directories exist of the file that is returned. Because of the LogUtil.makeLogFile contract, it is guaranteed that any such newly created directories will be subdirectories of the log directory. Therefore, this is a safe operation.

Returns:
a new File constructed from childPath
Throws:
IllegalArgumentException - if childPath is blank; childPath resolves to a path that falls outside the log directory
SecurityException - if a security manager exists and denies read access to the file
RuntimeException - (or some subclass) if any other error occurs; this may merely wrap some other underlying Throwable

copy

public static void copy(File source,
                        File target,
                        boolean append)
                 throws IllegalArgumentException,
                        IllegalStateException,
                        SecurityException,
                        IOException
Copies source to target.

Parameters:
source - the File that will read bytes from
target - the File that will write bytes to
append - only relevant if target already exists: if true, then adds source's bytes to end of target, if false, then overwrites target
Throws:
IllegalArgumentException - if source is not valid; target == null; source and target resolve to the same path
SecurityException - if a security manager exists and its SecurityManager.checkRead(java.lang.String) method denies access to source or target
IOException - if an I/O problem occurs
IllegalStateException

delete

public static void delete(File file)
                   throws IllegalArgumentException,
                          SecurityException,
                          IOException
Trys to delete file, and throws an IOException if the delete failed. It is useful because File.delete unfortunately merely returns a boolean indicating the success of the operation, rather than throwing an Exception.

Note: DirUtil.delete should be used to delete directories.

Parameters:
file - a normal file that is to be deleted
Throws:
IllegalArgumentException - if file is not valid
SecurityException - if a security manager exists and denies read access to the file
IOException - if an I/O problem occurs; this includes failure of the file to be deleted

deleteIfExists

public static void deleteIfExists(File file)
                           throws IllegalArgumentException,
                                  SecurityException,
                                  IOException
Calls delete(file) if file != null and file exists.

Note: delete will do some additional tests of file (that it is a normal file that can be read by this application).

Note: DirUtil.deleteIfExists should be used to delete directories if they exist.

Parameters:
file - a normal file that is to be deleted; may be null or non-existent
Throws:
IllegalArgumentException - if file is not a normal file
SecurityException - if a security manager exists and denies read access to the file
IOException - if an I/O problem occurs; this includes failure of the file to be deleted

move

public static File move(File file,
                        File directory)
                 throws IllegalArgumentException,
                        SecurityException,
                        IOException
Moves file into directory.

This is a convenience method that simply returns rename(file, new File(directory, file.getName()).

Parameters:
file - the file to move
directory - the directory to move file into
Returns:
a new File instance whose path is for the new location of file after the move
Throws:
IllegalArgumentException - if file is not valid; directory is not valid; rename finds an issue
SecurityException - if a security manager exists and denies write access to file or directory
IOException - if an I/O problem occurs; this includes failure of the file to be renamed

rename

public static File rename(File file1,
                          File file2)
                   throws IllegalArgumentException,
                          SecurityException,
                          IOException
Trys to rename file1 to file2. Since file2 may be in a different directory and/or have a different name, this is really a combined move/rename method.

This method was written because File.renameTo unfortunately merely returns a boolean indicating the success of the operation, which forces the user to check. In contrast, this method corrects that defect and throws an Exception instead.

Furthermore, for maximum safety, this method will never overwrite an existing but different file. Therefore, it insists that file2 must not currently exist unless it is equal to file1. (One reason why the user may wish to supply file2 equal to file1 is if their operating system has case insensitive file names: perhaps they are simply trying to change file1's name to a standard case.)

Note: DirUtil.rename should be used to rename directories.

Parameters:
file1 - the currently existing file
file2 - the file that is to be renamed to
Returns:
file2
Throws:
IllegalArgumentException - if file1 is not valid; file2 == null; file2 already exists and is not equal to file1
SecurityException - if a security manager exists and denies write access to file1 or file2
IOException - if an I/O problem occurs; this includes failure of the file to be renamed

readBytes

public static byte[] readBytes(File file)
                        throws IllegalArgumentException,
                               IllegalStateException,
                               SecurityException,
                               IOException
Reads file's contents into a byte[] which is returned.

Throws:
IllegalArgumentException - if file is not valid
IllegalStateException - if file holds more than Integer.MAX_VALUE bytes (which cannot be held in a java array)
SecurityException - if a security manager exists and its SecurityManager.checkRead(java.lang.String) method denies read access to file
IOException - if an I/O problem occurs

readBytesEnd

public static byte[] readBytesEnd(File file,
                                  int n)
                           throws IllegalArgumentException,
                                  SecurityException,
                                  IOException
Reads the final part of file's contents into a byte[] which is returned. The number of bytes in the result is the minimum of n or file's length. The byte order of the result is the same as the order in the file.

Throws:
IllegalArgumentException - if file is not valid
SecurityException - if a security manager exists and its SecurityManager.checkRead(java.lang.String) method denies read access to file
IOException - if an I/O problem occurs

readAsciiToChars

public static char[] readAsciiToChars(File file)
                               throws IllegalArgumentException,
                                      IllegalStateException,
                                      SecurityException,
                                      IOException
Reads file's contents into a byte[] (using the readBytes method), converts that into a char[] (using the StringUtil.asciiBytesToChars method) returns the char[]. So, the data inside file must consist only of US-ASCII bytes.

Throws:
IllegalArgumentException - if file is not valid; file cannot be read by this application; a non-ascii byte (i.e. a negative value) is encountered
IllegalStateException - if file holds more than Integer.MAX_VALUE bytes (which cannot be held in a java array)
SecurityException - if a security manager exists and its SecurityManager.checkRead(java.lang.String) method denies read access to file
IOException - if an I/O problem occurs

readChars

public static char[] readChars(File file)
                        throws IllegalArgumentException,
                               IllegalStateException,
                               SecurityException,
                               IOException
Reads file's contents into a byte[] (using readBytes), converts that into a char[] (using StringUtil.bytesToChars), and then returns the char[]. So, the data inside file must be encoded using this platform's default encoding.

Throws:
IllegalArgumentException - if file is not valid; file cannot be read by this application
IllegalStateException - if file holds more than Integer.MAX_VALUE bytes (which cannot be held in a java array)
SecurityException - if a security manager exists and its SecurityManager.checkRead(java.lang.String) method denies read access to file
IOException - (or a subclass, like MalformedInputException or UnmappableCharacterException) if an I/O problem occurs

readString

public static String readString(File file)
                         throws IllegalArgumentException,
                                IllegalStateException,
                                SecurityException,
                                IOException
Returns new String( readBytes(file) ). Note: the platform's default char encoding is implicitly used to convert the bytes into a String. So, the data inside file must be encoded using this platform's default encoding.

Throws:
IllegalArgumentException - if file is not valid; file cannot be read by this application
IllegalStateException - if file holds more than Integer.MAX_VALUE bytes (which cannot be held in a java array)
SecurityException - if a security manager exists and its SecurityManager.checkRead(java.lang.String) method denies read access to file
IOException - if an I/O problem occurs

writeBytes

public static void writeBytes(byte[] bytes,
                              File file,
                              boolean append)
                       throws IllegalArgumentException,
                              SecurityException,
                              IOException
Writes bytes into file. All resources (e.g. OutputStreams) that are created as part of this process will be closed upon method return.

Parameters:
append - specifies whether to append to an existing file or to overwrite its contents
Throws:
IllegalArgumentException - if bytes is null; file is null; file is a directory
SecurityException - if a security manager exists and its SecurityManager.checkRead(java.lang.String) method denies write access to file
IOException - if an I/O problem occurs

writeString

public static void writeString(String string,
                               File file,
                               boolean append)
                        throws IllegalArgumentException,
                               SecurityException,
                               IOException
Simply executes writeBytes( string.getBytes(), file, append ). Note: that call to string.getBytes implicitly uses the platform's default char encoding to convert the String into a byte[].

Parameters:
append - specifies whether to append to an existing file or to overwrite its contents
Throws:
IllegalArgumentException - if string is null; file is null; file is a directory
SecurityException - if a security manager exists and its SecurityManager.checkRead(java.lang.String) method denies write access to file
IOException - if an I/O problem occurs

compareContents

public static long compareContents(File file1,
                                   File file2)
                            throws IllegalArgumentException,
                                   SecurityException,
                                   IOException
Compares the contents of the two supplied normal files, byte by byte. Returns the (zero-based) index of the first byte position where they differ, else returns -1 if they are identical. If one file is smaller than the other, but the bytes in the 2 files are identical up to where the smaller ends, then the value returned is the length of the smaller file (i.e. the index of the first extra byte in the larger file).

Contract: the result is -1 if and only the files are identical, else is >= 0.

Throws:
IllegalArgumentException - if file1 or file2 is not valid;
SecurityException - if a security manager exists and denies read access to either file
IOException - if an I/O problem occurs

calcBufferSize

private static int calcBufferSize(File file1,
                                  File file2)

findWhereDiffer

private static int findWhereDiffer(byte[] bytes1,
                                   byte[] bytes2,
                                   int limit)

canEncode

private static boolean canEncode(char c)
Determines whether or not this platform's default Charset) can encode c and then decode it back to the exact same value.

The issue with some platforms is that they cannot handle certain chars correctly. For example, windoze is notorious in that its default CharSet, Cp1252, has the following strange behavior:

[Cp1252 is] Microsoft Windows variant of Latin-1, NT default. Beware. Some unexpected translations occur when you read with this default encoding, e.g. codes 128..159 are translated to 16 bit chars with bits in the high order byte on. It does not just truncate the high byte on write and pad with 0 on read. For true Latin-1 see 8859-1.
See the Java glossary article on encoding for more details.

This method is fairly expensive to call: you should never use it on every char that you wish to encode. It is currently only used in the UnitTest class, and is private.