这是我的 Java 7 解决方案,适用于已知父路径且相对子路径可能与磁盘上的路径不同的情况。
例如,给定文件/tmp/foo/biscuits
,该方法将Path
使用以下输入正确地将 a 返回到文件:
/tmp
和foo/biscuits
/tmp
和foo/BISCUITS
/tmp
和FOO/BISCUITS
/tmp
和FOO/biscuits
请注意,此解决方案尚未经过可靠测试,因此应将其视为起点,而不是可用于生产的片段。
/**
* Returns an absolute path with a known parent path in a case-insensitive manner.
*
* <p>
* If the underlying filesystem is not case-sensitive or <code>relativeChild</code> has the same
* case as the path on disk, this method is equivalent to returning
* <code>parent.resolve(relativeChild)</code>
* </p>
*
* @param parent parent to search for child in
* @param relativeChild relative child path of potentially mixed-case
* @return resolved absolute path to file, or null if none found
* @throws IOException
*/
public static Path getCaseInsensitivePath(Path parent, Path relativeChild) throws IOException {
// If the path can be resolved, return it directly
if (isReadable(parent.resolve(relativeChild))) {
return parent.resolve(relativeChild);
}
// Recursively construct path
return buildPath(parent, relativeChild);
}
private static Path buildPath(Path parent, Path relativeChild) throws IOException {
return buildPath(parent, relativeChild, 0);
}
/**
* Recursively searches for and constructs a case-insensitive path
*
* @param parent path to search for child
* @param relativeChild relative child path to search for
* @param offset child name component
* @return target path on disk, or null if none found
* @throws IOException
*/
private static Path buildPath(Path parent, Path relativeChild, int offset) throws IOException {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(parent)) {
for (Path entry : stream) {
String entryFilename = entry.getFileName().toString();
String childComponent = relativeChild.getName(offset).toString();
/*
* If the directory contains a file or folder corresponding to the current component of the
* path, either return the full path (if the directory entry is a file and we have iterated
* over all child path components), or recurse into the next child path component if the
* match is on a directory.
*/
if (entryFilename.equalsIgnoreCase(childComponent)) {
if (offset == relativeChild.getNameCount() - 1 && Files.isRegularFile(entry)) {
return entry;
}
else if (Files.isDirectory(entry)) {
return buildPath(entry, relativeChild, offset + 1);
}
}
}
}
// No matches found; path can't exist
return null;
}