Path.equals() returns 对于 Windows 10 上的两个不同文件夹(小写 m 和大写 M)为真
Path.equals() returns true for two different folders (lowercase m and uppercase M) on Windows 10
我创建了一个文件索引器,它在 Windows 7 和 Ubuntu.
中运行良好
自从我迁移到 Windows 10 后,我的代码一直在特定文件夹上出现错误,C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo
这个文件夹很特别,因为它包含具有小写和大写名称的文件夹,如果小写则完全相同。
问题是我查看了我所有的代码库,它没有 equalsIgnoreCase
或 toLowerCase
或 toUpperCase
.
的实例
最后我得出结论,Path.equals
return对于两个不同的文件夹是正确的,但事实并非如此。这会导致我的代码出现问题,因为 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:
Whether or not two path are equal depends on the file system implementation. In some cases the paths are compared without regard to case, and others are case sensitive.
我如何修复我的代码或 JVM,以便 Path.equals
return 对于大小写不同的两个不同文件夹为 false?
Path::equals
的 JavaDoc 指出:
Whether or not two path are equal depends on the file system implementation. In some cases the paths are compared without regard to case, and others are case sensitive. This method does not access the file system and the file is not required to exist. Where required, the isSameFile method may be used to check if two paths locate the same file.
由于您的 Path
未针对 FileSystem
进行测试,您应该使用 Files::isSameFile.
对于 NTFS 中几乎所有其他位置,Path.equals 是正确的。然而,"LXSS" 文件是使用不同于正常 Windows API 的东西创建的(例如 NtCreateFile using OBJECT_ATTRIBUTES 未指定 OBJ_CASE_INSENSITIVE)。
如果您尝试浏览 Windows 中的 "M" 和 "m",您会发现您只能进入其中一个,因为它们似乎具有相同的内容。因此,不仅 AppData 的某些部分难以区分,而且如果没有一点魔法,有些部分是完全无法访问的。
我创建了一个文件索引器,它在 Windows 7 和 Ubuntu.
中运行良好自从我迁移到 Windows 10 后,我的代码一直在特定文件夹上出现错误,C:\Users\Terminal\AppData\Local\lxss\rootfs\usr\share\terminfo
这个文件夹很特别,因为它包含具有小写和大写名称的文件夹,如果小写则完全相同。
问题是我查看了我所有的代码库,它没有 equalsIgnoreCase
或 toLowerCase
或 toUpperCase
.
最后我得出结论,Path.equals
return对于两个不同的文件夹是正确的,但事实并非如此。这会导致我的代码出现问题,因为 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:
Whether or not two path are equal depends on the file system implementation. In some cases the paths are compared without regard to case, and others are case sensitive.
我如何修复我的代码或 JVM,以便 Path.equals
return 对于大小写不同的两个不同文件夹为 false?
Path::equals
的 JavaDoc 指出:
Whether or not two path are equal depends on the file system implementation. In some cases the paths are compared without regard to case, and others are case sensitive. This method does not access the file system and the file is not required to exist. Where required, the isSameFile method may be used to check if two paths locate the same file.
由于您的 Path
未针对 FileSystem
进行测试,您应该使用 Files::isSameFile.
对于 NTFS 中几乎所有其他位置,Path.equals 是正确的。然而,"LXSS" 文件是使用不同于正常 Windows API 的东西创建的(例如 NtCreateFile using OBJECT_ATTRIBUTES 未指定 OBJ_CASE_INSENSITIVE)。
如果您尝试浏览 Windows 中的 "M" 和 "m",您会发现您只能进入其中一个,因为它们似乎具有相同的内容。因此,不仅 AppData 的某些部分难以区分,而且如果没有一点魔法,有些部分是完全无法访问的。