Utility class for synchronizing files/directories : File Monoitor « File Input Output « Java






Utility class for synchronizing files/directories

    

//$Id: FileHelper.java 15522 2008-11-05 20:06:43Z hardy.ferentschik $

//Revised from hibernate search util
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;


/**
 * Utility class for synchronizing files/directories.
 *
 * @author Emmanuel Bernard
 * @author Sanne Grinovero
 * @author Hardy Ferentschik
 */
public abstract class FileHelper {

  private static final int FAT_PRECISION = 2000;
  public static final long DEFAULT_COPY_BUFFER_SIZE = 16 * 1024 * 1024; // 16 MB


  public static boolean areInSync(File source, File destination) throws IOException {
    if ( source.isDirectory() ) {
      if ( !destination.exists() ) {
        return false;
      }
      else if ( !destination.isDirectory() ) {
        throw new IOException(
            "Source and Destination not of the same type:"
                + source.getCanonicalPath() + " , " + destination.getCanonicalPath()
        );
      }
      String[] sources = source.list();
      Set<String> srcNames = new HashSet<String>( Arrays.asList( sources ) );
      String[] dests = destination.list();

      // check for files in destination and not in source
      for ( String fileName : dests ) {
        if ( !srcNames.contains( fileName ) ) {
          return false;
        }
      }

      boolean inSync = true;
      for ( String fileName : sources ) {
        File srcFile = new File( source, fileName );
        File destFile = new File( destination, fileName );
        if ( !areInSync( srcFile, destFile ) ) {
          inSync = false;
          break;
        }
      }
      return inSync;
    }
    else {
      if ( destination.exists() && destination.isFile() ) {
        long sts = source.lastModified() / FAT_PRECISION;
        long dts = destination.lastModified() / FAT_PRECISION;
        return sts == dts;
      }
      else {
        return false;
      }
    }
  }

  public static void synchronize(File source, File destination, boolean smart) throws IOException {
    synchronize( source, destination, smart, DEFAULT_COPY_BUFFER_SIZE );
  }

  public static void synchronize(File source, File destination, boolean smart, long chunkSize) throws IOException {
    if ( chunkSize <= 0 ) {
      System.out.println("Chunk size must be positive: using default value." );
      chunkSize = DEFAULT_COPY_BUFFER_SIZE;
    }
    if ( source.isDirectory() ) {
      if ( !destination.exists() ) {
        if ( !destination.mkdirs() ) {
          throw new IOException( "Could not create path " + destination );
        }
      }
      else if ( !destination.isDirectory() ) {
        throw new IOException(
            "Source and Destination not of the same type:"
                + source.getCanonicalPath() + " , " + destination.getCanonicalPath()
        );
      }
      String[] sources = source.list();
      Set<String> srcNames = new HashSet<String>( Arrays.asList( sources ) );
      String[] dests = destination.list();

      //delete files not present in source
      for ( String fileName : dests ) {
        if ( !srcNames.contains( fileName ) ) {
          delete( new File( destination, fileName ) );
        }
      }
      //copy each file from source
      for ( String fileName : sources ) {
        File srcFile = new File( source, fileName );
        File destFile = new File( destination, fileName );
        synchronize( srcFile, destFile, smart, chunkSize );
      }
    }
    else {
      if ( destination.exists() && destination.isDirectory() ) {
        delete( destination );
      }
      if ( destination.exists() ) {
        long sts = source.lastModified() / FAT_PRECISION;
        long dts = destination.lastModified() / FAT_PRECISION;
        //do not copy if smart and same timestamp and same length
        if ( !smart || sts == 0 || sts != dts || source.length() != destination.length() ) {
          copyFile( source, destination, chunkSize );
        }
      }
      else {
        copyFile( source, destination, chunkSize );
      }
    }
  }

  private static void copyFile(File srcFile, File destFile, long chunkSize) throws IOException {
    FileInputStream is = null;
    FileOutputStream os = null;
    try {
      is = new FileInputStream( srcFile );
      FileChannel iChannel = is.getChannel();
      os = new FileOutputStream( destFile, false );
      FileChannel oChannel = os.getChannel();
      long doneBytes = 0L;
      long todoBytes = srcFile.length();
      while ( todoBytes != 0L ) {
        long iterationBytes = Math.min( todoBytes, chunkSize );
        long transferredLength = oChannel.transferFrom( iChannel, doneBytes, iterationBytes );
        if ( iterationBytes != transferredLength ) {
          throw new IOException(
              "Error during file transfer: expected "
                  + iterationBytes + " bytes, only " + transferredLength + " bytes copied."
          );
        }
        doneBytes += transferredLength;
        todoBytes -= transferredLength;
      }
    }
    finally {
      if ( is != null ) {
        is.close();
      }
      if ( os != null ) {
        os.close();
      }
    }
    boolean successTimestampOp = destFile.setLastModified( srcFile.lastModified() );
    if ( !successTimestampOp ) {
      System.out.println("Could not change timestamp for {}. Index synchronization may be slow. " + destFile );
    }
  }

  public static void delete(File file) {
    if ( file.isDirectory() ) {
      for ( File subFile : file.listFiles() ) {
        delete( subFile );
      }
    }
    if ( file.exists() ) {
      if ( !file.delete() ) {
        System.out.println( "Could not delete {}" + file );
      }
    }
  }
}

   
    
    
    
  








Related examples in the same category

1.File Monitor Demo
2.Monitoring a File for changes.
3.Monitor files for changes