public static Boolean contentEquals ( Path file1 , Path file2 ) throws IOException { if ( ! java . nio . file . Files . isRegularFile ( file1 ) ) throw new IllegalArgumentException ( file1 + "is not a regular file" ) ; if ( ! java . nio . file . Files . isRegularFile ( file2 ) ) throw new IllegalArgumentException ( file2 + "is not a regular file" ) ; FileChannel channel1 = null ; FileChannel channel2 = null ; MappedByteBuffer buffer1 = null ; MappedByteBuffer buffer2 = null ; try { long size1 = java . nio . file . Files . size ( file1 ) ; long size2 = java . nio . file . Files . size ( file2 ) ; if ( size1 != size2 ) return false ; long position = 0 ; long length = Math . min ( Integer . MAX_VALUE , size1 - position ) ; channel1 = FileChannel . open ( file1 ) ; channel2 = FileChannel . open ( file2 ) ; // Cannot map files larger than Integer.MAX_VALUE, // so we have to do it in pieces. while ( length > 0 ) { buffer1 = channel1 . map ( MapMode . READ_ONLY , position , length ) ; buffer2 = channel2 . map ( MapMode . READ_ONLY , position , length ) ; // if (!buffer1.equals(buffer2)) return false; // The line above is much slower than the line below. // It should not be, but it is, possibly because it is // loading the entire buffer into memory before comparing // the contents. See the corresponding unit test. EK for ( int i = 0 ; i < length ; i ++ ) if ( buffer1 . get ( ) != buffer2 . get ( ) ) return false ; position += length ; length = Math . min ( Integer . MAX_VALUE , size1 - position ) ; cleanDirectByteBuffer ( buffer1 ) ; buffer1 = null ; cleanDirectByteBuffer ( buffer2 ) ; buffer2 = null ; } } finally { // Is is important to clean up so we do not hold any // file locks, in case the caller wants to do something // else with the files. // In terms of functional programming, holding a lock after // returning to the caller would be an unwelcome side-effect. cleanDirectByteBuffer ( buffer1 ) ; cleanDirectByteBuffer ( buffer2 ) ; if ( channel1 != null ) try { channel1 . close ( ) ; } catch ( IOException e ) { if ( channel2 != null ) channel2 . close ( ) ; throw e ; } if ( channel2 != null ) channel2 . close ( ) ; } return true ; }
Identical File Contents