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 ); } } } }
1. | File Monitor Demo | ||
2. | Monitoring a File for changes. | ||
3. | Monitor files for changes |