gt:         IOFileFilter effDirFilter = setUpEffectiveDirFilter(dirFilter);
context: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   * 
   *      http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.commons.io;
  
  import java.io.File;
  import java.io.FileFilter;
  import java.io.FileInputStream;
  import java.io.FileNotFoundException;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.io.OutputStream;
  import java.io.Reader;
  import java.math.BigInteger;
  import java.net.URL;
  import java.net.URLConnection;
  import java.nio.ByteBuffer;
  import java.nio.channels.FileChannel;
  import java.nio.charset.Charset;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Date;
  import java.util.Iterator;
  import java.util.List;
  import java.util.zip.CRC32;
  import java.util.zip.CheckedInputStream;
  import java.util.zip.Checksum;
  
  import org.apache.commons.io.filefilter.DirectoryFileFilter;
  import org.apache.commons.io.filefilter.FalseFileFilter;
  import org.apache.commons.io.filefilter.FileFilterUtils;
  import org.apache.commons.io.filefilter.IOFileFilter;
  import org.apache.commons.io.filefilter.SuffixFileFilter;
  import org.apache.commons.io.filefilter.TrueFileFilter;
  import org.apache.commons.io.output.NullOutputStream;
  
  /**
   * General file manipulation utilities.
   * <p>
   * Facilities are provided in the following areas:
   * <ul>
   * <li>writing to a file
   * <li>reading from a file
   * <li>make a directory including parent directories
   * <li>copying files and directories
   * <li>deleting files and directories
   * <li>converting to and from a URL
   * <li>listing files and directories by filter and extension
   * <li>comparing file content
   * <li>file last changed date
   * <li>calculating a checksum
   * </ul>
   * <p>
   * Origin of code: Excalibur, Alexandria, Commons-Utils
   *
   * @version $Id: FileUtils.java 1304052 2012-03-22 20:55:29Z ggregory $
   */
  public class FileUtils {
  
      /**
       * Instances should NOT be constructed in standard programming.
       */
      public FileUtils() {
          super();
      }
  
      /**
       * The number of bytes in a kilobyte.
       */
      public static final long ONE_KB = 1024;
  
      /**
       * The number of bytes in a megabyte.
       */
      public static final long ONE_MB = ONE_KB * ONE_KB;
  
      /**
       * The file copy buffer size (30 MB)
       */
      private static final long FILE_COPY_BUFFER_SIZE = ONE_MB * 30;
  
      /**
       * The number of bytes in a gigabyte.
       */
      public static final long ONE_GB = ONE_KB * ONE_MB;
  
      /**
       * The number of bytes in a terabyte.
       */
      public static final long ONE_TB = ONE_KB * ONE_GB;
  
      /**
       * The number of bytes in a petabyte.
       */
      public static final long ONE_PB = ONE_KB * ONE_TB;
  
      /**
       * The number of bytes in an exabyte.
       */
      public static final long ONE_EB = ONE_KB * ONE_PB;
  
      /**
       * The number of bytes in a zettabyte.
       */
      public static final BigInteger ONE_ZB = BigInteger.valueOf(ONE_KB).multiply(BigInteger.valueOf(ONE_EB));
  
      /**
       * The number of bytes in a yottabyte.
       */
      public static final BigInteger ONE_YB = ONE_ZB.multiply(BigInteger.valueOf(ONE_EB));
  
      /**
       * An empty array of type <code>File</code>.
       */
      public static final File[] EMPTY_FILE_ARRAY = new File[0];
  
      /**
       * The UTF-8 character set, used to decode octets in URLs.
       */
      private static final Charset UTF8 = Charset.forName("UTF-8");
  
      //-----------------------------------------------------------------------
      /**
       * Construct a file from the set of name elements.
       * 
       * @param directory the parent directory
       * @param names the name elements
       * @return the file
       * @since 2.1
       */
      public static File getFile(File directory, String... names) {
          if (directory == null) {
              throw new NullPointerException("directorydirectory must not be null");
          }
          if (names == null) {
              throw new NullPointerException("names must not be null");
          }
          File file = directory;
          for (String name : names) {
              file = new File(file, name);
          }
          return file;
      }
  
      /**
       * Construct a file from the set of name elements.
       * 
       * @param names the name elements
       * @return the file
       * @since 2.1
       */
      public static File getFile(String... names) {
          if (names == null) {
              throw new NullPointerException("names must not be null");
          }
          File file = null;
          for (String name : names) {
              if (file == null) {
                  file = new File(name);
              } else {
                  file = new File(file, name);
              }
          }
          return file;
      }
  
      /**
       * Returns the path to the system temporary directory.
       * 
       * @return the path to the system temporary directory.
       * 
       * @since 2.0
       */
      public static String getTempDirectoryPath() {
          return System.getProperty("java.io.tmpdir");
      }
      
      /**
       * Returns a {@link File} representing the system temporary directory.
       * 
       * @return the system temporary directory. 
       * 
       * @since 2.0
       */
      public static File getTempDirectory() {
          return new File(getTempDirectoryPath());
      }
      
      /**
       * Returns the path to the user's home directory.
       * 
       * @return the path to the user's home directory.
       * 
       * @since 2.0
       */
      public static String getUserDirectoryPath() {
          return System.getProperty("user.home");
      }
      
      /**
       * Returns a {@link File} representing the user's home directory.
       * 
       * @return the user's home directory.
       * 
       * @since 2.0
       */
      public static File getUserDirectory() {
          return new File(getUserDirectoryPath());
      }
      
      //-----------------------------------------------------------------------
      /**
       * Opens a {@link FileInputStream} for the specified file, providing better
       * error messages than simply calling <code>new FileInputStream(file)</code>.
       * <p>
       * At the end of the method either the stream will be successfully opened,
       * or an exception will have been thrown.
       * <p>
       * An exception is thrown if the file does not exist.
       * An exception is thrown if the file object exists but is a directory.
       * An exception is thrown if the file exists but cannot be read.
       * 
       * @param file  the file to open for input, must not be <code>null</code>
       * @return a new {@link FileInputStream} for the specified file
       * @throws FileNotFoundException if the file does not exist
       * @throws IOException if the file object is a directory
       * @throws IOException if the file cannot be read
       * @since 1.3
       */
      public static FileInputStream openInputStream(File file) throws IOException {
          if (file.exists()) {
              if (file.isDirectory()) {
                  throw new IOException("File '" + file + "' exists but is a directory");
              }
              if (file.canRead() == false) {
                  throw new IOException("File '" + file + "' cannot be read");
              }
          } else {
              throw new FileNotFoundException("File '" + file + "' does not exist");
          }
          return new FileInputStream(file);
      }
  
      //-----------------------------------------------------------------------
      /**
       * Opens a {@link FileOutputStream} for the specified file, checking and
       * creating the parent directory if it does not exist.
       * <p>
       * At the end of the method either the stream will be successfully opened,
       * or an exception will have been thrown.
       * <p>
       * The parent directory will be created if it does not exist.
       * The file will be created if it does not exist.
       * An exception is thrown if the file object exists but is a directory.
       * An exception is thrown if the file exists but cannot be written to.
       * An exception is thrown if the parent directory cannot be created.
       * 
       * @param file  the file to open for output, must not be <code>null</code>
       * @return a new {@link FileOutputStream} for the specified file
       * @throws IOException if the file object is a directory
       * @throws IOException if the file cannot be written to
       * @throws IOException if a parent directory needs creating but that fails
       * @since 1.3
       */
      public static FileOutputStream openOutputStream(File file) throws IOException {
          return openOutputStream(file, false);
      }
  
      /**
       * Opens a {@link FileOutputStream} for the specified file, checking and
       * creating the parent directory if it does not exist.
       * <p>
       * At the end of the method either the stream will be successfully opened,
       * or an exception will have been thrown.
       * <p>
       * The parent directory will be created if it does not exist.
       * The file will be created if it does not exist.
       * An exception is thrown if the file object exists but is a directory.
       * An exception is thrown if the file exists but cannot be written to.
       * An exception is thrown if the parent directory cannot be created.
       * 
       * @param file  the file to open for output, must not be <code>null</code>
       * @param append if <code>true</code>, then bytes will be added to the
       * end of the file rather than overwriting
       * @return a new {@link FileOutputStream} for the specified file
       * @throws IOException if the file object is a directory
       * @throws IOException if the file cannot be written to
       * @throws IOException if a parent directory needs creating but that fails
       * @since 2.1
       */
      public static FileOutputStream openOutputStream(File file, boolean append) throws IOException {
          if (file.exists()) {
              if (file.isDirectory()) {
                  throw new IOException("File '" + file + "' exists but is a directory");
              }
              if (file.canWrite() == false) {
                  throw new IOException("File '" + file + "' cannot be written to");
              }
          } else {
              File parent = file.getParentFile();
              if (parent != null) {
                  if (!parent.mkdirs() && !parent.isDirectory()) {
                      throw new IOException("Directory '" + parent + "' could not be created");
                  }
              }
          }
          return new FileOutputStream(file, append);
      }
  
      //-----------------------------------------------------------------------
      /**
       * Returns a human-readable version of the file size, where the input
       * represents a specific number of bytes.
       * 
       * If the size is over 1GB, the size is returned as the number of whole GB,
       * i.e. the size is rounded down to the nearest GB boundary.
       * 
       * Similarly for the 1MB and 1KB boundaries.
       *
       * @param size  the number of bytes
       * @return a human-readable display value (includes units - GB, MB, KB or bytes)
       */
      // See https://issues.apache.org/jira/browse/IO-226 - should the rounding be changed?
      public static String byteCountToDisplaySize(long size) {
          String displaySize;
  
          if (size / ONE_EB > 0) {
              displaySize = String.valueOf(size / ONE_EB) + " EB";
          } else if (size / ONE_PB > 0) {
              displaySize = String.valueOf(size / ONE_PB) + " PB";
          } else if (size / ONE_TB > 0) {
              displaySize = String.valueOf(size / ONE_TB) + " TB";
          } else 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;
      }
  
      //-----------------------------------------------------------------------
      /**
       * Implements the same behaviour as the "touch" utility on Unix. 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.
       * <p>
       * NOTE: As from v1.3, this method throws an IOException if the last
       * modified date of the file cannot be set. Also, as from v1.3 this method
       * creates parent directories if they do not exist.
       *
       * @param file  the File to touch
       * @throws IOException If an I/O problem occurs
       */
      public static void touch(File file) throws IOException {
          if (!file.exists()) {
              OutputStream out = openOutputStream(file);
              IOUtils.closeQuietly(out);
          }
          boolean success = file.setLastModified(System.currentTimeMillis());
          if (!success) {
              throw new IOException("Unable to set the last modification time for " + file);
          }
      }
  
      //-----------------------------------------------------------------------
      /**
       * Converts a Collection containing java.io.File instanced into array
       * representation. This is to account for the difference between
       * File.listFiles() and FileUtils.listFiles().
       *
       * @param files  a Collection containing java.io.File instances
       * @return an array of java.io.File
       */
      public static File[] convertFileCollectionToFileArray(Collection<File> files) {
           return files.toArray(new File[files.size()]);
      }
  
      //-----------------------------------------------------------------------
      /**
       * Finds files within a given directory (and optionally its
       * subdirectories). All files found are filtered by an IOFileFilter.
       *
       * @param files the collection of files found.
       * @param directory the directory to search in.
       * @param filter the filter to apply to files and directories.
       * @param includeSubDirectories indicates if will include the subdirectories themselves
       */
      private static void innerListFiles(Collection<File> files, File directory,
              IOFileFilter filter, boolean includeSubDirectories) {
          File[] found = directory.listFiles((FileFilter) filter);
          
          if (found != null) {
              for (File file : found) {
                  if (file.isDirectory()) {
                      if (includeSubDirectories) {
                          files.add(file);
                      }
                      innerListFiles(files, file, filter, includeSubDirectories);
                  } else {
                      files.add(file);
                  }
              }
          }
      }
  
      /**
       * Finds files within a given directory (and optionally its
       * subdirectories). All files found are filtered by an IOFileFilter.
       * <p>
       * If your search should recurse into subdirectories you can pass in
       * an IOFileFilter for directories. You don't need to bind a
       * DirectoryFileFilter (via logical AND) to this filter. This method does
       * that for you.
       * <p>
       * An example: If you want to search through all directories called
       * "temp" you pass in <code>FileFilterUtils.NameFileFilter("temp")</code>
       * <p>
       * Another common usage of this method is find files in a directory
       * tree but ignoring the directories generated CVS. You can simply pass
       * in <code>FileFilterUtils.makeCVSAware(null)</code>.
       *
       * @param directory  the directory to search in
       * @param fileFilter  filter to apply when finding files.
       * @param dirFilter  optional filter to apply when finding subdirectories.
       * If this parameter is <code>null</code>, subdirectories will not be included in the
       * search. Use TrueFileFilter.INSTANCE to match all directories.
       * @return an collection of java.io.File with the matching files
       * @see org.apache.commons.io.filefilter.FileFilterUtils
       * @see org.apache.commons.io.filefilter.NameFileFilter
       */
      public static Collection<File> listFiles(
              File directory, IOFileFilter fileFilter, IOFileFilter dirFilter) {
          validateListFilesParameters(directory, fileFilter);
  
          IOFileFilter effFileFilter = setUpEffectiveFileFilter(fileFilter);
          IOFileFilter effDirFilter = setUpEffectiveDirFilter(dirFilter);
  
          //Find files
          Collection<File> files = new java.util.LinkedList<File>();
          innerListFiles(files, directory,
              FileFilterUtils.or(effFileFilter, effDirFilter), false);
          return files;
      }
  
      /**
       * Validates the given arguments.
       * <ul>
       * <li>Throws {@link IllegalArgumentException} if {@code directory} is not a directory</li>
       * <li>Throws {@link NullPointerException} if {@code fileFilter} is null</li>
       * </ul>
       * 
       * @param directory The File to test
       * @param fileFilter The IOFileFilter to test
       */
      private static void validateListFilesParameters(File directory, IOFileFilter fileFilter) {
          if (!directory.isDirectory()) {
              throw new IllegalArgumentException("Parameter 'directory' is not a directory");
          }
          if (fileFilter == null) {
              throw new NullPointerException("Parameter 'fileFilter' is null");
          }
      }
  
      /**
       * Returns a filter that accepts files in addition to the {@link File} objects accepted by the given filter.
       * 
       * @param fileFilter a base filter to add to
       * @return a filter that accepts files 
       */
      private static IOFileFilter setUpEffectiveFileFilter(IOFileFilter fileFilter) {
          return FileFilterUtils.and(fileFilter, FileFilterUtils.notFileFilter(DirectoryFileFilter.INSTANCE));
      }
  
      /**
       * Returns a filter that accepts directories in addition to the {@link File} objects accepted by the given filter.
       * 
       * @param dirFilter a base filter to add to
       * @return a filter that accepts directories 
       */
      private static IOFileFilter setUpEffectiveDirFilter(IOFileFilter dirFilter) {
          return dirFilter == null ? FalseFileFilter.INSTANCE : FileFilterUtils.and(dirFilter,
                  DirectoryFileFilter.INSTANCE);
      }
  
      /**
       * Finds files within a given directory (and optionally its
       * subdirectories). All files found are filtered by an IOFileFilter.
       * <p>
       * The resulting collection includes the subdirectories themselves.
       * <p>
       * @see org.apache.commons.io.FileUtils#listFiles  
       *
       * @param directory  the directory to search in
       * @param fileFilter  filter to apply when finding files.
       * @param dirFilter  optional filter to apply when finding subdirectories.
       * If this parameter is <code>null</code>, subdirectories will not be included in the
       * search. Use TrueFileFilter.INSTANCE to match all directories.
       * @return an collection of java.io.File with the matching files
       * @see org.apache.commons.io.filefilter.FileFilterUtils
       * @see org.apache.commons.io.filefilter.NameFileFilter
       * @since 2.2
       */
      public static Collection<File> listFilesAndDirs(
              File directory, IOFileFilter fileFilter, IOFileFilter dirFilter) {
          validateListFilesParameters(directory, fileFilter);
  
          IOFileFilter effFileFilter = setUpEffectiveFileFilter(fileFilter);
  