Open Source Repository

Home /jodd/jodd-3.3.2 | Repository Home


jodd/io/FileUtil.java
// Copyright (c) 2003-2012, Jodd Team (jodd.org). All Rights Reserved.

package jodd.io;

import jodd.JoddDefault;
import jodd.util.StringPool;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.RandomAccessFile;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.FileFilter;
import java.io.Writer;
import java.net.URI;
import java.net.URL;
import java.util.List;
import java.util.ArrayList;

/**
 * File utilities.
 */
public class FileUtil {

  private static final String READ_ONLY = "r";
  private static final String MSG_NOT_A_DIRECTORY = "Not a directory: ";
  private static final String MSG_CANT_CREATE = "Can't create: ";
  private static final String MSG_NOT_FOUND = "Not found: ";
  private static final String MSG_NOT_A_FILE = "Not a file: ";
  private static final String MSG_ALREADY_EXISTS = "Already exists: ";
  private static final String MSG_UNABLE_TO_DELETE = "Unable to delete: ";

  // ---------------------------------------------------------------- misc shortcuts

  /**
   * Checks if two files points to the same file.
   */
  public static boolean equals(String file1, String file2) {
    return equals(new File(file1)new File(file2));
  }

  /**
   * Checks if two files points to the same file.
   */
  public static boolean equals(File file1, File file2) {
    try {
      file1 = file1.getCanonicalFile();
      file2 = file2.getCanonicalFile();
    catch (IOException ignore) {
      return false;
    }
    return file1.equals(file2);
  }

  /**
   * Converts URI to file. Returns <code>null</code> in case of invalid URI.
   */
  public static File toFile(URI uri) {
    try {
      return new File(uri);
    catch (IllegalArgumentException ignore) {
      return null;
    }
  }

  /**
   * Converts file URLs to file. Ignores other schemes and returns <code>null</code>.
   */
  public static File toFile(URL url) {
    String fileName = toFileName(url);
    if (fileName == null) {
      return null;
    }
    return new File(fileName);
  }

  /**
   * Converts file URLs to file name. Ignores other schemes and returns <code>null</code>.
   */
  public static String toFileName(URL url) {
    if ((url == null|| (url.getProtocol().equals("file"== false)) {
      return null;
    }
    String filename = url.getFile().replace('/', File.separatorChar);
    int pos = 0;
    while ((pos = filename.indexOf('%', pos)) >= 0) {
      if (pos + < filename.length()) {
        String hexStr = filename.substring(pos + 1, pos + 3);
        char ch = (charInteger.parseInt(hexStr, 16);
        filename = filename.substring(0, pos+ ch + filename.substring(pos + 3);
      }
    }
    return filename;
  }

  /**
   * Converts array of URLS to file names string. Other schemes are ignored.
   */
  public static String toFileNames(URL[] urls) {
    StringBuilder path = new StringBuilder();
    for (URL url : urls) {
      String fileName = toFileName(url);
      if (fileName == null) {
        continue;
      }
      path.append(fileName).append(File.pathSeparatorChar);
    }
    return path.toString();
  }


  // ---------------------------------------------------------------- mkdirs

  /**
   * Creates all folders at once.
   */
  public static void mkdirs(String dirsthrows IOException {
    mkdirs(new File(dirs));
  }
  /**
   * Creates all folders at once.
   */
  public static void mkdirs(File dirsthrows IOException {
    if (dirs.exists()) {
      if (dirs.isDirectory() == false) {
        throw new IOException(MSG_NOT_A_DIRECTORY + dirs);
      }
      return;
    }
    if (dirs.mkdirs() == false) {
      throw new IOException(MSG_CANT_CREATE + dirs);
    }
  }

  /**
   * Creates single folder.
   */
  public static void mkdir(String dirthrows IOException {
    mkdir(new File(dir));
  }
  /**
   * Creates single folders.
   */
  public static void mkdir(File dirthrows IOException {
    if (dir.exists()) {
      if (dir.isDirectory() == false) {
        throw new IOException(MSG_NOT_A_DIRECTORY + dir);
      }
      return;
    }
    if (dir.mkdir() == false) {
      throw new IOException(MSG_CANT_CREATE + dir);
    }
  }

  // ---------------------------------------------------------------- touch

  /**
   {@link #touch(java.io.File)}
   */
  public static void touch(String filethrows IOException {
    touch(new File(file));
  }

  /**
   * Implements the Unix "touch" utility. It creates a new file
   * with size 0 or, if the file exists already, it is opened and
   * closed without modifying it, but updating the file date and time.
   */
  public static void touch(File filethrows IOException {
    if (file.exists() == false) {
      StreamUtil.close(new FileOutputStream(file));
    }
    file.setLastModified(System.currentTimeMillis());
  }


  // ---------------------------------------------------------------- params

  // default global FileUtilParams
  public static FileUtilParams defaultParams = new FileUtilParams();

  /**
   * Creates new {@link FileUtilParams} instance by cloning current default params.
   */
  public static FileUtilParams cloneParams() {
    try {
      return defaultParams.clone();
    catch (CloneNotSupportedException ignore) {
      return null;
    }
  }

  /**
   * Creates new {@link FileUtilParams} instance with default values.
   */
  public static FileUtilParams params() {
    return new FileUtilParams();
  }

  // ---------------------------------------------------------------- copy file to file

  public static void copyFile(String src, String destthrows IOException {
    copyFile(new File(src)new File(dest), defaultParams);
  }

  public static void copyFile(String src, String dest, FileUtilParams paramsthrows IOException {
    copyFile(new File(src)new File(dest), params);
  }

  public static void copyFile(File src, File destthrows IOException {
    copyFile(src, dest, defaultParams);
  }

  /**
   * Copies a file to another file with specified copy params.
   */
  public static void copyFile(File src, File dest, FileUtilParams paramsthrows IOException {
    checkFileCopy(src, dest, params);
    doCopyFile(src, dest, params);
  }

  private static void checkFileCopy(File src, File dest, FileUtilParams paramsthrows IOException {
    if (src.exists() == false) {
      throw new FileNotFoundException(MSG_NOT_FOUND + src);
    }
    if (src.isFile() == false) {
      throw new IOException(MSG_NOT_A_FILE + src);
    }
    if (equals(src, dest== true) {
      throw new IOException("Files '" + src + "' and '" + dest + "' are equal.");
    }

    File destParent = dest.getParentFile();
    if (destParent != null && destParent.exists() == false) {
      if (params.createDirs == false) {
        throw new IOException(MSG_NOT_FOUND + destParent);
      }
      if (destParent.mkdirs() == false) {
        throw new IOException(MSG_CANT_CREATE + destParent);
      }
    }
  }

  /**
   * Internal file copy when most of the pre-checking has passed.
   */
  private static void doCopyFile(File src, File dest, FileUtilParams paramsthrows IOException {
    if (dest.exists()) {
      if (dest.isDirectory()) {
        throw new IOException("Destination '" + dest + "' is a directory.");
      }
      if (params.overwrite == false) {
        throw new IOException(MSG_ALREADY_EXISTS + dest);
      }
    }

    doCopy(src, dest);

    if (src.length() != dest.length()) {
      throw new IOException("Copy file failed of '" + src + "' to '" + dest + "' due to different sizes.");
    }
    if (params.preserveDate) {
      dest.setLastModified(src.lastModified());
    }
  }

  // ---------------------------------------------------------------- simple copy file

  /**
   * Copies one file to another without any checking.
   @see #doCopy(java.io.File, java.io.File)
   */
  protected static void doCopy(String src, String destthrows IOException {
    doCopy(new File(src)new File(dest));
  }

  /**
   * Copies one file to another without any checking. It is assumed that
   * both parameters represents valid files.
   */
  protected static void doCopy(File src, File destthrows IOException {
    FileInputStream input = new FileInputStream(src);
    try {
      FileOutputStream output = new FileOutputStream(dest);
      try {
        StreamUtil.copy(input, output);
      finally {
        StreamUtil.close(output);
      }
    finally {
      StreamUtil.close(input);
    }
  }


  // ---------------------------------------------------------------- copy file to directory

  /**
   @see #copyFileToDir(java.io.File, java.io.File, FileUtilParams)
   */
  public static File copyFileToDir(String src, String destDirthrows IOException {
    return copyFileToDir(new File(src)new File(destDir), defaultParams);
  }
  /**
   @see #copyFileToDir(java.io.File, java.io.File, FileUtilParams)
   */
  public static File copyFileToDir(String src, String destDir, FileUtilParams paramsthrows IOException {
    return copyFileToDir(new File(src)new File(destDir), params);
  }
  /**
   @see #copyFileToDir(java.io.File, java.io.File, FileUtilParams)
   */
  public static File copyFileToDir(File src, File destDirthrows IOException {
    return copyFileToDir(src, destDir, defaultParams);
  }
  /**
   * Copies a file to folder with specified copy params and returns copied destination.
   */
  public static File copyFileToDir(File src, File destDir, FileUtilParams paramsthrows IOException {
    if (destDir.exists() && destDir.isDirectory() == false) {
      throw new IOException(MSG_NOT_A_DIRECTORY + destDir);
    }
    File dest = new File(destDir, src.getName());
    copyFile(src, dest, params);
    return dest;
  }


  // ---------------------------------------------------------------- copy dir


  public static void copyDir(String srcDir, String destDirthrows IOException {
    copyDir(new File(srcDir)new File(destDir), defaultParams);
  }

  public static void copyDir(String srcDir, String destDir, FileUtilParams paramsthrows IOException {
    copyDir(new File(srcDir)new File(destDir), params);
  }

  public static void copyDir(File srcDir, File destDirthrows IOException {
    copyDir(srcDir, destDir, defaultParams);
  }

  /**
   * Copies directory with specified copy params.
   */
  public static void copyDir(File srcDir, File destDir, FileUtilParams paramsthrows IOException {
    checkDirCopy(srcDir, destDir);
    doCopyDirectory(srcDir, destDir, params);
  }

  private static void checkDirCopy(File srcDir, File destDirthrows IOException {
    if (srcDir.exists() == false) {
      throw new FileNotFoundException(MSG_NOT_FOUND + srcDir);
    }
    if (srcDir.isDirectory() == false) {
      throw new IOException(MSG_NOT_A_DIRECTORY + srcDir);
    }
    if (equals(srcDir, destDir== true) {
      throw new IOException("Source '" + srcDir + "' and destination '" + destDir + "' are equal.");
    }
  }

  private static void doCopyDirectory(File srcDir, File destDir, FileUtilParams paramsthrows IOException {
    if (destDir.exists()) {
      if (destDir.isDirectory() == false) {
        throw new IOException(MSG_NOT_A_DIRECTORY + destDir);
      }
    else {
      if (params.createDirs == false) {
        throw new IOException(MSG_NOT_FOUND + destDir);
      }
      if (destDir.mkdirs() == false) {
        throw new IOException(MSG_CANT_CREATE + destDir);
      }
      if (params.preserveDate) {
        destDir.setLastModified(srcDir.lastModified());
      }
    }

    File[] files = srcDir.listFiles();
    if (files == null) {
      throw new IOException("Failed to list contents of: " + srcDir);
    }

    IOException exception = null;
    for (File file : files) {
      File destFile = new File(destDir, file.getName());
      try {
        if (file.isDirectory()) {
          if (params.recursive == true) {
            doCopyDirectory(file, destFile, params);
          }
        else {
          doCopyFile(file, destFile, params);
        }
      catch (IOException ioex) {
        if (params.continueOnError == true) {
          exception = ioex;
          continue;
        }
        throw ioex;
      }
    }

    if (exception != null) {
      throw exception;
    }
  }



  // ---------------------------------------------------------------- move file

  public static void moveFile(String src, String destthrows IOException {
    moveFile(new File(src)new File(dest), defaultParams);
  }

  public static void moveFile(String src, String dest, FileUtilParams paramsthrows IOException {
    moveFile(new File(src)new File(dest), params);
  }

  public static void moveFile(File src, File destthrows IOException {
    moveFile(src, dest, defaultParams);
  }

  public static void moveFile(File src, File dest, FileUtilParams paramsthrows IOException {
    checkFileCopy(src, dest, params);
    doMoveFile(src, dest, params);
  }

  private static void doMoveFile(File src, File dest, FileUtilParams paramsthrows IOException {
    if (dest.exists()) {
      if (dest.isFile() == false) {
        throw new IOException(MSG_NOT_A_FILE + dest);
      }
      if (params.overwrite == false) {
        throw new IOException(MSG_ALREADY_EXISTS + dest);
      }
      dest.delete();
    }

    if (src.renameTo(dest== false) {
      throw new IOException("Move failed: '" + src + "' to '" + dest + "'.");
    }
  }

  // ---------------------------------------------------------------- move file to dir


  public static void moveFileToDir(String src, String destDirthrows IOException {
    moveFileToDir(new File(src)new File(destDir), defaultParams);
  }
  public static void moveFileToDir(String src, String destDir, FileUtilParams paramsthrows IOException {
    moveFileToDir(new File(src)new File(destDir), params);
  }

  public static void moveFileToDir(File src, File destDirthrows IOException {
    moveFileToDir(src, destDir, defaultParams);
  }
  public static void moveFileToDir(File src, File destDir, FileUtilParams paramsthrows IOException {
    if (destDir.exists() && destDir.isDirectory() == false) {
      throw new IOException(MSG_NOT_A_DIRECTORY + destDir);
    }
    moveFile(src, new File(destDir, src.getName()), params);
  }




  // ---------------------------------------------------------------- move dir

  public static void moveDir(String srcDir, String destDirthrows IOException {
    moveDir(new File(srcDir)new File(destDir));
  }

  public static void moveDir(File srcDir, File destDirthrows IOException {
    checkDirCopy(srcDir, destDir);
    doMoveDirectory(srcDir, destDir);
  }

  private static void doMoveDirectory(File src, File destthrows IOException {
    if (dest.exists()) {
      if (dest.isDirectory() == false) {
        throw new IOException(MSG_NOT_A_DIRECTORY + dest);
      }
      dest = new File(dest, dest.getName());
      dest.mkdir();
    }

    if (src.renameTo(dest== false) {
      throw new IOException("Move failed: '" + src + "' to '" + dest + "'.");
    }
  }



  // ---------------------------------------------------------------- delete file

  public static void deleteFile(String destthrows IOException {
    deleteFile(new File(dest));
  }

  public static void deleteFile(File destthrows IOException {
    if (dest.exists() == false) {
      throw new FileNotFoundException(MSG_NOT_FOUND + dest);
    }
    if (dest.isFile() == false) {
      throw new IOException(MSG_NOT_A_FILE + dest);
    }
    if (dest.delete() == false) {
      throw new IOException(MSG_UNABLE_TO_DELETE + dest);
    }
  }


  // ---------------------------------------------------------------- delete dir

  public static void deleteDir(String destthrows IOException {
    deleteDir(new File(dest), defaultParams);
  }
  public static void deleteDir(String dest, FileUtilParams paramsthrows IOException {
    deleteDir(new File(dest), params);
  }
  public static void deleteDir(File destthrows IOException {
    deleteDir(dest, defaultParams);
  }
  /**
   * Deletes a directory.
   */
  public static void deleteDir(File dest, FileUtilParams paramsthrows IOException {
    cleanDir(dest, params);
    if (dest.delete() == false) {
      throw new IOException(MSG_UNABLE_TO_DELETE + dest);
    }
  }



  public static void cleanDir(String destthrows IOException {
    cleanDir(new File(dest), defaultParams);
  }

  public static void cleanDir(String dest, FileUtilParams paramsthrows IOException {
    cleanDir(new File(dest), params);
  }

  public static void cleanDir(File destthrows IOException {
    cleanDir(dest, defaultParams);
  }

  /**
   * Cleans a directory without deleting it.
   */
  public static void cleanDir(File dest, FileUtilParams paramsthrows IOException {
    if (dest.exists() == false) {
      throw new FileNotFoundException(MSG_NOT_FOUND + dest);
    }

    if (dest.isDirectory() == false) {
      throw new IOException(MSG_NOT_A_DIRECTORY + dest);
    }

    File[] files = dest.listFiles();
    if (files == null) {
      throw new IOException("Failed to list contents of: " + dest);
    }

    IOException exception = null;
    for (File file : files) {
      try {
        if (file.isDirectory()) {
          if (params.recursive == true) {
            deleteDir(file, params);
          }
        else {
          file.delete();
        }
      catch (IOException ioex) {
        if (params.continueOnError == true) {
          exception = ioex;
          continue;
        }
        throw ioex;
      }
    }

    if (exception != null) {
      throw exception;
    }
  }

  // ---------------------------------------------------------------- read/write chars

  public static char[] readChars(String fileNamethrows IOException {
    return readChars(new File(fileName), defaultParams.encoding);
  }

  public static char[] readChars(File filethrows IOException {
    return readChars(file, defaultParams.encoding);
  }

  public static char[] readChars(String fileName, String encodingthrows IOException {
    return readChars(new File(fileName), encoding);
  }

  /**
   * Reads file content as char array.
   */
  public static char[] readChars(File file, String encodingthrows IOException {
    if (file.exists() == false) {
      throw new FileNotFoundException(MSG_NOT_FOUND + file);
    }
    if (file.isFile() == false) {
      throw new IOException(MSG_NOT_A_FILE + file);
    }
    long len = file.length();
    if (len >= Integer.MAX_VALUE) {
      len = Integer.MAX_VALUE;
    }
    FileInputStream in = null;
    try {
      in = new FileInputStream(file);
      FastCharArrayWriter fastCharArrayWriter = new FastCharArrayWriter((intlen);
      StreamUtil.copy(in, fastCharArrayWriter, encoding);
      return fastCharArrayWriter.toCharArray();
    finally {
      StreamUtil.close(in);
    }
  }


  public static void writeChars(File dest, char[] datathrows IOException {
    outChars(dest, data, JoddDefault.encoding, false);
  }
  public static void writeChars(String dest, char[] datathrows IOException {
    outChars(new File(dest), data, JoddDefault.encoding, false);
  }

  public static void writeChars(File dest, char[] data, String encodingthrows IOException {
    outChars(dest, data, encoding, false);
  }
  public static void writeChars(String dest, char[] data, String encodingthrows IOException {
    outChars(new File(dest), data, encoding, false);
  }
  
  protected static void outChars(File dest, char[] data, String encoding, boolean appendthrows IOException {
    if (dest.exists() == true) {
      if (dest.isFile() == false) {
        throw new IOException(MSG_NOT_A_FILE + dest);
      }
    }
    Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dest, append), encoding));
    try {
      out.write(data);
    finally {
      StreamUtil.close(out);
    }
  }


  // ---------------------------------------------------------------- read/write string


  public static String readString(String sourcethrows IOException {
    return readString(new File(source), defaultParams.encoding);
  }

  public static String readString(String source, String encodingthrows IOException {
    return readString(new File(source), encoding);
  }

  public static String readString(File sourcethrows IOException {
    return readString(source, defaultParams.encoding);
  }

  /**
   * Reads file content as string.
   */
  public static String readString(File file, String encodingthrows IOException {
    if (file.exists() == false) {
      throw new FileNotFoundException(MSG_NOT_FOUND + file);
    }
    if (file.isFile() == false) {
      throw new IOException(MSG_NOT_A_FILE + file);
    }
    long len = file.length();
    if (len >= Integer.MAX_VALUE) {
      len = Integer.MAX_VALUE;
    }
    FileInputStream in = null;
    try {
      in = new FileInputStream(file);
      FastCharArrayWriter out = new FastCharArrayWriter((intlen);
      StreamUtil.copy(in, out, encoding);
      return out.toString();
    finally {
      StreamUtil.close(in);
    }
  }


  public static void writeString(String dest, String datathrows IOException {
    outString(new File(dest), data, defaultParams.encoding, false);
  }

  public static void writeString(String dest, String data, String encodingthrows IOException {
    outString(new File(dest), data, encoding, false);
  }

  public static void writeString(File dest, String datathrows IOException {
    outString(dest, data, defaultParams.encoding, false);
  }

  public static void writeString(File dest, String data, String encodingthrows IOException {
    outString(dest, data, encoding, false);
  }


  public static void appendString(String dest, String datathrows IOException {
    outString(new File(dest), data, defaultParams.encoding, true);
  }

  public static void appendString(String dest, String data, String encodingthrows IOException {
    outString(new File(dest), data, encoding, true);
  }

  public static void appendString(File dest, String datathrows IOException {
    outString(dest, data, defaultParams.encoding, true);
  }

  public static void appendString(File dest, String data, String encodingthrows IOException {
    outString(dest, data, encoding, true);
  }

  protected static void outString(File dest, String data, String encoding, boolean appendthrows IOException {
    if (dest.exists() == true) {
      if (dest.isFile() == false) {
        throw new IOException(MSG_NOT_A_FILE + dest);
      }
    }
    FileOutputStream out = null;
    try {
      out = new FileOutputStream(dest, append);
      out.write(data.getBytes(encoding));
    finally {
      StreamUtil.close(out);
    }
  }

  // ---------------------------------------------------------------- stream

  public static void writeStream(File dest, InputStream inthrows IOException {
    FileOutputStream out = null;
    try {
      out = new FileOutputStream(dest);
      StreamUtil.copy(in, out);
    finally {
      StreamUtil.close(out);
    }

  }

  public static void writeStream(String dest, InputStream inthrows IOException {
    FileOutputStream out = null;
    try {
      out = new FileOutputStream(dest);
      StreamUtil.copy(in, out);
    finally {
      StreamUtil.close(out);
    }
  }


  // ---------------------------------------------------------------- read/write string lines


  public static String[] readLines(String sourcethrows IOException {
    return readLines(new File(source), defaultParams.encoding);
  }
  public static String[] readLines(String source, String encodingthrows IOException {
    return readLines(new File(source), encoding);
  }
  public static String[] readLines(File sourcethrows IOException {
    return readLines(source, defaultParams.encoding);
  }

  /**
   * Reads lines from source files.
   */
  public static String[] readLines(File file, String encodingthrows IOException {
    if (file.exists() == false) {
      throw new FileNotFoundException(MSG_NOT_FOUND + file);
    }
    if (file.isFile() == false) {
      throw new IOException(MSG_NOT_A_FILE + file);
    }
    List<String> list = new ArrayList<String>();
    FileInputStream in = null;
    try {
      in = new FileInputStream(file);
      BufferedReader br = new BufferedReader(new InputStreamReader(in, encoding));
      String strLine;
      while ((strLine = br.readLine()) != null)   {
        list.add(strLine);
      }
    finally {
      StreamUtil.close(in);
    }
    return list.toArray(new String[list.size()]);
  }



  // ---------------------------------------------------------------- read/write bytearray


  public static byte[] readBytes(String filethrows IOException {
    return readBytes(new File(file));
  }

  public static byte[] readBytes(File filethrows IOException {
    if (file.exists() == false) {
      throw new FileNotFoundException(MSG_NOT_FOUND + file);
    }
    if (file.isFile() == false) {
      throw new IOException(MSG_NOT_A_FILE + file);
    }
    long len = file.length();
    if (len >= Integer.MAX_VALUE) {
      throw new IOException("File is larger then max array size.");
    }

    byte[] bytes = new byte[(intlen];
    RandomAccessFile randomAccessFile = new RandomAccessFile(file, READ_ONLY);
    randomAccessFile.readFully(bytes);
    randomAccessFile.close();

    return bytes;
  }



  public static void writeBytes(String dest, byte[] datathrows IOException {
    outBytes(new File(dest), data, 0, data.length, false);
  }

  public static void writeBytes(String dest, byte[] data, int off, int lenthrows IOException {
    outBytes(new File(dest), data, off, len, false);
  }

  public static void writeBytes(File dest, byte[] datathrows IOException {
    outBytes(dest, data, 0, data.length, false);
  }

  public static void writeBytes(File dest, byte[] data, int off, int lenthrows IOException {
    outBytes(dest, data, off, len, false);
  }


  public static void appendBytes(String dest, byte[] datathrows IOException {
    outBytes(new File(dest), data, 0, data.length, true);
  }

  public static void appendBytes(String dest, byte[] data, int off, int lenthrows IOException {
    outBytes(new File(dest), data, off, len, true);
  }

  public static void appendBytes(File dest, byte[] datathrows IOException {
    outBytes(dest, data, 0, data.length, true);
  }

  public static void appendBytes(File dest, byte[] data, int off, int lenthrows IOException {
    outBytes(dest, data, off, len, true);
  }

  protected static void outBytes(File dest, byte[] data, int off, int len, boolean appendthrows IOException {
    if (dest.exists() == true) {
      if (dest.isFile() == false) {
        throw new IOException(MSG_NOT_A_FILE + dest);
      }
    }
    FileOutputStream out = null;
    try {
      out = new FileOutputStream(dest, append);
      out.write(data, off, len);
    finally {
      StreamUtil.close(out);
    }
  }

  // ---------------------------------------------------------------- equals content

  public static boolean compare(String file1, String file2throws IOException {
    return compare(new File(file1)new File(file2));
  }

  /**
   * Compare the contents of two files to determine if they are equal or
   * not.
   <p>
   * This method checks to see if the two files are different lengths
   * or if they point to the same file, before resorting to byte-by-byte
   * comparison of the contents.
   <p>
   * Code origin: Avalon
   */
  public static boolean compare(File file1, File file2throws IOException {
    boolean file1Exists = file1.exists();
    if (file1Exists != file2.exists()) {
      return false;
    }

    if (file1Exists == false) {
      return true;
    }

    if ((file1.isFile() == false|| (file2.isFile() == false)) {
      throw new IOException("Only files can be compared.");
    }

    if (file1.length() != file2.length()) {
      return false;
    }

    if (equals(file1, file1)) {
      return true;
    }

    InputStream input1 = null;
    InputStream input2 = null;
    try {
      input1 = new FileInputStream(file1);
      input2 = new FileInputStream(file2);
      return StreamUtil.compare(input1, input2);
    finally {
      StreamUtil.close(input1);
      StreamUtil.close(input2);
    }
  }

  // ---------------------------------------------------------------- time

  public static boolean isNewer(String file, String reference) {
    return isNewer(new File(file)new File(reference));
  }

  /**
   * Test if specified <code>File</code> is newer than the reference <code>File</code>.
   *
   @param file    the <code>File</code> of which the modification date must be compared
   @param reference  the <code>File</code> of which the modification date is used
   @return <code>true</code> if the <code>File</code> exists and has been modified more
   *       recently than the reference <code>File</code>.
   */
  public static boolean isNewer(File file, File reference) {
    if (reference.exists() == false) {
      throw new IllegalArgumentException("Reference file not found: " + reference);
    }
    return isNewer(file, reference.lastModified());
  }


  public static boolean isOlder(String file, String reference) {
    return isOlder(new File(file)new File(reference));
  }

  public static boolean isOlder(File file, File reference) {
    if (reference.exists() == false) {
      throw new IllegalArgumentException("Reference file not found: " + reference);
    }
    return isOlder(file, reference.lastModified());
  }

  /**
   * Tests if the specified <code>File</code> is newer than the specified time reference.
   *
   @param file      the <code>File</code> of which the modification date must be compared.
   @param timeMillis  the time reference measured in milliseconds since the
   *             epoch (00:00:00 GMT, January 1, 1970)
   @return <code>true</code> if the <code>File</code> exists and has been modified after
   *         the given time reference.
   */
  public static boolean isNewer(File file, long timeMillis) {
    if (!file.exists()) {
      return false;
    }
    return file.lastModified() > timeMillis;
  }

  public static boolean isNewer(String file, long timeMillis) {
    return isNewer(new File(file), timeMillis);
  }


  public static boolean isOlder(File file, long timeMillis) {
    if (!file.exists()) {
      return false;
    }
    return file.lastModified() < timeMillis;
  }

  public static boolean isOlder(String file, long timeMillis) {
    return isOlder(new File(file), timeMillis);
  }


  // ---------------------------------------------------------------- smart copy

  public static void copy(String src, String destthrows IOException {
    copy(new File(src)new File(dest), defaultParams);
  }

  public static void copy(String src, String dest, FileUtilParams paramsthrows IOException {
    copy(new File(src)new File(dest), params);
  }

  public static void copy(File src, File destthrows IOException {
    copy(src, dest, defaultParams);
  }
  /**
   * Smart copy. If source is a directory, copy it to destination.
   * Otherwise, if destination is directory, copy source file to it.
   * Otherwise, try to copy source file to destination file.
   */
  public static void copy(File src, File dest, FileUtilParams paramsthrows IOException {
    if (src.isDirectory() == true) {
      copyDir(src, dest, params);
      return;
    }
    if (dest.isDirectory() == true) {
      copyFileToDir(src, dest, params);
      return;
    }
    copyFile(src, dest, params);
  }

  // ---------------------------------------------------------------- smart move

  public static void move(String src, String destthrows IOException {
    move(new File(src)new File(dest), defaultParams);
  }

  public static void move(String src, String dest, FileUtilParams paramsthrows IOException {
    move(new File(src)new File(dest), params);
  }

  public static void move(File src, File destthrows IOException {
    move(src, dest, defaultParams);
  }
  /**
   * Smart move. If source is a directory, move it to destination.
   * Otherwise, if destination is directory, move source file to it.
   * Otherwise, try to move source file to destination file.
   */
  public static void move(File src, File dest, FileUtilParams paramsthrows IOException {
    if (src.isDirectory() == true) {
      moveDir(src, dest);
      return;
    }
    if (dest.isDirectory() == true) {
      moveFileToDir(src, dest, params);
      return;
    }
    moveFile(src, dest, params);
  }


  // ---------------------------------------------------------------- smart delete

  public static void delete(String destthrows IOException {
    delete(new File(dest), defaultParams);
  }

  public static void delete(String dest, FileUtilParams paramsthrows IOException {
    delete(new File(dest), params);
  }

  public static void delete(File destthrows IOException {
    delete(dest, defaultParams);
  }

  /**
   * Smart delete of destination file or directory.
   */
  public static void delete(File dest, FileUtilParams paramsthrows IOException {
    if (dest.isDirectory()) {
      deleteDir(dest, params);
      return;
    }
    deleteFile(dest);
  }

  // ---------------------------------------------------------------- misc

  /**
   * Check if one file is an ancestor of second one.
   *
   @param strict   if <code>false</code> then this method returns <code>true</code> if ancestor
   *                 and file are equal
   @return <code>true</code> if ancestor is parent of file; <code>false</code> otherwise
   */
  public static boolean isAncestor(File ancestor, File file, boolean strict) {
    File parent = strict ? getParentFile(file: file;
    while (true) {
      if (parent == null) {
        return false;
      }
      if (parent.equals(ancestor)) {
        return true;
      }
      parent = getParentFile(parent);
    }
  }

  /**
   * Returns parent for the file. The method correctly
   * processes "." and ".." in file names. The name
   * remains relative if was relative before.
   * Returns <code>null</code> if the file has no parent.
   */
  public static File getParentFile(final File file) {
    int skipCount = 0;
    File parentFile = file;
    while (true) {
      parentFile = parentFile.getParentFile();
      if (parentFile == null) {
        return null;
      }
      if (StringPool.DOT.equals(parentFile.getName())) {
        continue;
      }
      if (StringPool.DOTDOT.equals(parentFile.getName())) {
        skipCount++;
        continue;
      }
      if (skipCount > 0) {
        skipCount--;
        continue;
      }
      return parentFile;
    }
  }

  public static boolean isFilePathAcceptable(File file, FileFilter fileFilter) {
    do {
      if (fileFilter != null && !fileFilter.accept(file)) {
        return false;
      }
      file = file.getParentFile();
    while (file != null);
    return true;
  }

  // ---------------------------------------------------------------- temp

  public static File createTempDirectory(String prefix, String suffixthrows IOException {
    return createTempDirectory(prefix, suffix, (Filenull);
  }
  public static File createTempDirectory(String prefix, String suffix, String tempDirNamethrows IOException {
    return createTempDirectory(prefix, suffix, new File(tempDirName));
  }
  /**
   * Creates temporary directory.
   */
  public static File createTempDirectory(String prefix, String suffix, File tempDirthrows IOException {
    File file = doCreateTempFile(prefix, suffix, tempDir);
    file.delete();
    file.mkdir();
    return file;
  }

  public static File createTempFile() throws IOException {
    return createTempFile(true);
  }
  public static File createTempFile(boolean createthrows IOException {
    return createTempFile(JoddDefault.tempFilePrefix, ".tmp"(Filenull, create);
  }
  public static File createTempFile(String prefix, String suffixthrows IOException {
    return createTempFile(prefix, suffix, (Filenull, true);
  }
  public static File createTempFile(String prefix, String suffix, boolean createthrows IOException {
    return createTempFile(prefix, suffix, (Filenull, create);
  }
  public static File createTempFile(String prefix, String suffix, String tempDirNamethrows IOException {
    return createTempFile(prefix, suffix, new File(tempDirName)true);
  }
  public static File createTempFile(String prefix, String suffix, File tempDirthrows IOException {
    return createTempFile(prefix, suffix, tempDir, true);
  }
  public static File createTempFile(String prefix, String suffix, String tempDirName, boolean createthrows IOException {
    return createTempFile(prefix, suffix, new File(tempDirName), create);
  }
  /**
   * Creates temporary file.
   * If <code>create</code> is set to <code>true</code> file will be
   * physically created on the file system. Otherwise, it will be created and then
   * deleted - trick that will make temp file exist only if they are used.
   */
  public static File createTempFile(String prefix, String suffix, File tempDir, boolean createthrows IOException {
    File file = doCreateTempFile(prefix, suffix, tempDir);
    file.delete();
    if (create) {
      file.createNewFile();
    }
    return file;
  }

  private static File doCreateTempFile(String prefix, String suffix, File dirthrows IOException {
    int exceptionsCount = 0;
    while (true) {
      try {
        return File.createTempFile(prefix, suffix, dir).getCanonicalFile();
      catch (IOException ioex) {  // fixes java.io.WinNTFileSystem.createFileExclusively access denied
        if (++exceptionsCount >= 100) {
          throw ioex;
        }
      }
    }
  }

}