Path.equals()在Windows 10上为两个不同的文件夹(小写的m和大写的M)返回true

时间:2017-04-23 13:16:34

标签: java windows java-8 windows-10 windows-subsystem-for-linux

我已经创建了一个文件索引器,它在Windows 7和Ubuntu中运行良好。

自从我迁移到Windows 10后,我的代码一直在特定文件夹上出现错误,C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo

此文件夹是特别的,因为它包含小写和大写名称的文件夹,如果小写,则相同。

screenshot of folder

问题在于,我查看了所有代码库,并且没有equalsIgnoreCasetoLowerCasetoUpperCase的实例。

最后我得出结论,Path.equals对于两个不同的文件夹返回true,它不应该。这导致我的代码出现问题,因为Path被用作Map关于代码中所有位置的关键字,特别是在我的索引器实现中,这会导致Collectors.groupingBy对属于不同的文件夹放在同一个文件夹中:

    Map<Path, List<DetailedFileReference>> parentFolderToDetailList = finderResult.getDetails().stream()
            .collect(Collectors.groupingBy(o -> o.asPathObject().getParent()));

我能够找出复制步骤:

Path originFolder = Paths.get("C:\\Users\\Terminal\\AppData\\Local\\lxss\\rootfs\\usr\\share\\terminfo");
Path lowercaseFolder = originFolder.resolve("m");
Path uppercaseFolder = originFolder.resolve("M");

if (lowercaseFolder.equals(uppercaseFolder)) {
    System.out.println(lowercaseFolder.toString() + " is equal to " + uppercaseFolder.toString());
}

此代码打印:

C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\m is equal to C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\M

然而,事实证明其他Java代码确实看到了这两个文件夹之间的区别,因为Files.walk只是工作正常:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public final class DuplicateFileIndexing {
    public static void main(String[] args) throws IOException {
        Path originFolder = Paths.get("C:\\Users\\Terminal\\AppData\\Local\\lxss\\rootfs\\usr\\share\\terminfo");
        Path lowercaseFolder = originFolder.resolve("m");
        Path uppercaseFolder = originFolder.resolve("M");

        System.out.println(originFolder.toAbsolutePath().toString());

        List<String> directoriesInOriginFolder = Files.walk(originFolder, 1)
                .filter(path -> Files.isDirectory(path))
                .map(path -> path.getFileName().toString())
                .collect(Collectors.toList());
        System.out.println(directoriesInOriginFolder);

        if (directoriesInOriginFolder.contains("m")) {
            System.out.println("Has a m folder");
        }
        if (directoriesInOriginFolder.contains("M")) {
            System.out.println("Has a M folder");
        }

        System.out.println("---");

        System.out.println("Files in 'm' folder");
        Files.walk(lowercaseFolder, 1)
                .map(path -> path.toAbsolutePath().toString())
                .forEach(System.out::println);

        System.out.println("---");

        System.out.println("Files in 'M' folder");
        Files.walk(uppercaseFolder, 1)
                .map(path -> path.toAbsolutePath().toString())
                .forEach(System.out::println);

        System.out.println("---");

        System.out.println("Parent of files in 'm' folder");
        Files.walk(lowercaseFolder, 1)
                .map(path -> path.toAbsolutePath().toString() + " is a child of " + path.getParent().toString())
                .forEach(System.out::println);

        System.out.println("---");

        System.out.println("Parent of files in 'M' folder");
        Files.walk(uppercaseFolder, 1)
                .map(path -> path.toAbsolutePath().toString() + " is a child of " + path.getParent().toString())
                .forEach(System.out::println);

        System.out.println("---");

        if (lowercaseFolder.equals(uppercaseFolder)) {
            System.out.println(lowercaseFolder.toString() + " is equal to " + uppercaseFolder.toString());
        }
    }
}

打印:

C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo
[terminfo, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, a, b, c, d, E, e, f, g, h, i, j, k, L, l, M, m, N, n, o, P, p, Q, q, r, s, t, u, v, w, X, x, z]
Has a m folder
Has a M folder
---
Files in 'm' folder
C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\m
C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\m\MtxOrb
C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\m\MtxOrb162
C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\m\MtxOrb204
---
Files in 'M' folder
C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\M
C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\M\MtxOrb
C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\M\MtxOrb162
C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\M\MtxOrb204
---
Parent of files in 'm' folder
C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\m is a child of C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo
C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\m\MtxOrb is a child of C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\m
C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\m\MtxOrb162 is a child of C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\m
C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\m\MtxOrb204 is a child of C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\m
---
Parent of files in 'M' folder
C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\M is a child of C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo
C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\M\MtxOrb is a child of C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\M
C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\M\MtxOrb162 is a child of C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\M
C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\M\MtxOrb204 is a child of C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\M
---
C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\m is equal to C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo\M

根据文件,Path.equals

  

两个路径是否相等取决于文件系统实现。在某些情况下,路径的比较与案例无关,而其他路径则区分大小写。

如何修复我的代码或JVM,以便Path.equals为两个不同的文件夹返回false?

2 个答案:

答案 0 :(得分:3)

Path::equals的JavaDoc声明:

  

两个路径是否相等取决于文件系统实现。在某些情况下,路径的比较与案例无关,而其他路径则区分大小写。此方法不访问文件系统,并且不需要存在该文件。如果需要,isSameFile方法可用于检查两个路径是否找到相同的文件。

由于Path未对FileSystem进行测试,因此您应使用Files::isSameFile

答案 1 :(得分:1)

对于NTFS中的几乎所有其他位置,Path.equals都是正确的。然而,&#34; LXSS&#34;文件是使用普通Windows API之外的其他东西创建的(例如NtCreateFile使用OBJECT_ATTRIBUTES未指定OBJ_CASE_INSENSITIVE)。

如果您尝试浏览&#34; M&#34;和&#34; m&#34;在Windows中,您会注意到您只能进入其中一个,因为它们似乎具有相同的内容。因此,不仅AppData的某些部分难以区分,而且有些部分在没有一点魔力的情况下无法实现。