I thought the result is true when Files.isSameFile invoke after fileB is copied from fileA, because fileA is same with fileB. However, the result is false.
Path pathA = Path.of("A.txt");
Path pathB = Path.of("B.txt");
Files.copy(pathA, pathB);
if(Files.isSameFile(pathA, pathB))
System.out.println("file is same");
else
System.out.println("file is not same"); // the result
I found that Files.isSameFile compare only String of Path.
How can I get true after copy? I want
Path pathA = Path.of("A.txt");
Path pathB = Path.of("B.txt");
Files.copy(pathA, pathB);
if(??) <-- I want
System.out.println("file is same");
CodePudding user response:
The API call you need is Files.mismatch(Path,Path) which returns -1 when the byte comparison of two files is same.
boolean identical = Files.mismatch(pathA, pathB) == -1;
As covered in other comments, Files.isSameFile deals with cases where two paths that are different could refer to the same underlying file on the filesystem. For example if I have directory "build" and file "build.xml":
Path a = Path.of("build.xml");
Path b = Path.of("build/../build.xml");
Files.isSameFile(a,b)
==> true
a.equals(b)
==> false
CodePudding user response:
I found that Files.isSameFile compare only String of Path.
That is not true. Javadoc says:
If both Path objects are equal then this method returns true without checking if the file exists. If the two Path objects are associated with different providers then this method returns false. Otherwise, this method checks if both Path objects locate the same file, and depending on the implementation, may require to open or access both files.
Method isSameFile() doesn't compare the contents, it's meant to define whether two paths point to the same location in the file system.
This method will return true if both paths are identical according to the equals method.
If it is not the case it'll try to access these paths.
If they represent the location in the file system that, i.e. one path is a symbolic link that point to another path isSameFile() will return true.
If both of them exit but do not lead to one another it'll return false.
And if at least one of them is not present in the file system it'll throw an exception.
public static void main(String[] args) throws IOException {
Path p1 = Paths.get("C:", "a", "b", "c", "test.txt");
Path p2 = Paths.get("C:",".", ".", ".", "FooBar", "..", "a", "b", "c", "test.txt");
Path p3 = p1.resolveSibling(Paths.get("copy.txt")); // path that leads to another file in the same folder
Path copy = Files.copy(p1, p3); // contents of p1 is being coped into p3, path to p3 is returned
System.out.println("Path 'p1': " p1);
System.out.println("Path 'p2`: " p2);
System.out.println("Path 'copy': " copy);
System.out.println("\np1 and p2 are the same: " Files.isSameFile(p1, p2));
System.out.println("p1 and copy are the same: " Files.isSameFile(p1, copy));
// Path p4 = Paths.get("C:", "a", "link.txt");
// Path symbolicLink = Files.createSymbolicLink(p4, p1);
// System.out.println("p1 and symbolicLink are the same: " Files.isSameFile(p1, symbolicLink));
}
Lines that deal with symbolic links are commented out because it cant be done in a such straightforward way. Symbolik links could introduce vulnerabilities and the system will not allow JVM to do this action. But if we assume that there is a symbolic link that points to p1 then Files.isSameFile(p1, symbolicLink) will return true
output
Path 'p1': C:\a\b\c\test.txt
Path 'p2`: C:\.\.\.\FooBar\..\a\b\c\test.txt
Path 'copy': C:\a\b\c\copy.txt
p1 and p2 are the same: true
p1 and copy are the same: false
To compare the actual contents of the files apart from Files.mismatch() which is accessible only with the latest long-term support version of Java you may create your own method that looks for desrapancies between the files like that:
private static boolean compareFiles(Path p1, Path p2) throws IOException {
boolean isSameFile = true;
try (var input1 = new BufferedInputStream(Files.newInputStream(p1));
var input2 = new BufferedInputStream(Files.newInputStream(p2))) {
byte[] buffer1 = new byte[1024];
byte[] buffer2 = new byte[1024];
int bytesRead1 = -1;
int bytesRead2 = -1;
while (isSameFile && bytesRead1 != 0 && bytesRead2 != 0) {
bytesRead1 = input1.readNBytes(buffer1, 0, buffer1.length);
bytesRead2 = input2.readNBytes(buffer2, 0, buffer2.length);
if (!Arrays.equals(buffer1, buffer2)) {
isSameFile = false;
}
}
}
return true;
}
