【问题标题】:Can I get sameFile is true after copy in Java nio?在Java nio中复制后我可以获得sameFile为真吗?
【发布时间】:2022-01-30 06:25:54
【问题描述】:

我认为在从fileA复制fileB之后调用Files.isSameFile时结果是true,因为fileA与fileB相同。但是,结果是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

我发现 Files.isSameFile 只比较路径字符串。

复制后如何获得真实?我想要

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"); 

【问题讨论】:

标签: java file nio java-io


【解决方案1】:

您需要的API调用是Files.mismatch(Path,Path),当两个文件的字节比较相同时返回-1。

boolean identical = Files.mismatch(pathA, pathB) == -1;

正如其他 cmets 中所述,Files.isSameFile 处理两个不同的路径可能引用文件系统上相同的底层文件的情况。例如,如果我有目录“build”和文件“build.xml”:

Path a = Path.of("build.xml");
Path b = Path.of("build/../build.xml");

Files.isSameFile(a,b)
==> true
a.equals(b)
==> false

还值得注意的是 - 在 JDK17 源代码中 - Files.mismatch 的第一步是 if (Files.isSameFile(a,b)) { return -1; };,这可以避免打开文件进行逐字节比较的需要。

【讨论】:

  • 感谢您的回答。我想要api。我将我的 java 版本 11 升级到 12。然后我执行了我的代码。结果是成功。
  • @Carmel 如果您需要比 11 更新的 Java 版本,那么您应该升级到 Java 17。不再支持 Java 12-16(Java 8、11 和 17 是“长期支持” )
【解决方案2】:

我发现 Files.isSameFile 只比较路径字符串。

不完全是。 Javadoc 说:

如果两个 Path 对象相等,则此方法返回 true 检查文件是否存在。如果两个 Path 对象关联 使用不同的提供者,则此方法返回 false。否则, 此方法检查两个 Path 对象是否找到相同的文件,并且 根据实现,可能需要同时打开或访问两者 文件。

方法isSameFile()不比较内容,它是用来定义是否two paths point to the same location in the file system

如果根据 equals() 方法两个路径相同,则此方法将返回 true。在这种情况下,none of these paths need to exist 用于实数和比较归结为您所说的字符串比较。

如果不是这种情况,它将尝试访问这些路径。 如果它们代表文件系统中的位置,即一个路径是 symbolic link,它指向另一个路径 isSameFile() 将返回 true。 如果他们两个都退出但不相互引导,它将返回false

如果文件系统中至少有一个不存在,它将引发异常。

    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));
    }

处理符号链接的行被注释掉,因为它不能以如此直接的方式完成。 Symbolik 链接可能会引入漏洞,系统将不允许 JVM 执行此操作。但是如果我们假设有一个指向 p1 的符号链接,那么Files.isSameFile(p1, symbolicLink) 将返回 true

输出

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

文件内容比较

对于apart from Files.mismatch() 中的compare the actual contents 文件,可以使用最新的Java 长期支持版本访问only ,您可以创建自己的方法来查找文件之间的差异,如下所示:

    public 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;
    }

【讨论】:

  • 它也很好用。我认为它在 java 11 版本中也很好。顺便说一句,变量的 isSameFile 不需要。使用 return insted 。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多