【问题标题】:Get file case-sensitive name, with case-insensitive spelling获取文件名区分大小写,拼写不区分大小写
【发布时间】:2012-02-03 17:17:54
【问题描述】:

我正在制作一个用户从中选择文件的应用程序:

FilePicker.PickFile(filename)

filename 是一个字符串。

在方法中,会翻译成:

File file = new File(filename);

这并没有什么问题。接下来,我愿意,

if(file.exists()){
    System.out.println(file.getName());
}
else{
    System.out.println("Fail.");
}

这就是问题的开始。我想获取文件的名称,比如“HELLO.txt”,但如果filename 是“hello.txt”,它仍然通过file.exists() 检查,并且file.getName() 返回为“hello.txt”不是“HELLO.txt”。有没有办法将file.getName() 作为区分大小写的版本返回为“HELLO.txt”?谢谢!

一个例子:

HELLO.txt is the real file

FilePicker.PickFile("hello.txt");

输出:

hello.txt

【问题讨论】:

  • 是的,我喜欢 linux,但我的 GPU 不能与内核一起工作 :(
  • 不幸的是,我认为没有解决方案。 NTFS 保留大小写,不区分大小写...

标签: java string file io


【解决方案1】:

当您使用 Windows 时,保留大小写 (FAT32/NTFS/..),您可以使用 file.getCanonicalFile().getName() 获取所选文件的规范名称。

当您使用 Linux 或 Android 时,如果您想根据不一定匹配大小写的文件名来选择文件,请遍历文件目录 (file.getParent()) 中的所有文件,然后选择 @987654326 中的文件@filename。或见Case-insensitive File.equals on case-sensitive file system

【讨论】:

  • 我发现此解决方案存在一个问题 - 它不适用于符号链接,因为根据文档的 getCanonicalFile 将解决符号链接!
  • 这个答案的第二个问题是它不适用于Android。所以删除线版本可能是要走的路。
【解决方案2】:

看起来在 Windows 上的 Java 7 及更高版本中,您可以使用 Path#toRealPath(NOFOLLOW_LINKS),并且在存在符号链接的情况下它会比 getCanonicalFile() 更正确。

【讨论】:

  • 你能进一步解释一下吗?
  • 上面链接的 Path#toRealPath() 的 API Docs 说:“它派生自这个路径,一个绝对路径,它定位与这个路径相同的文件,但名称元素代表实际名称的目录和文件”。这正是原始提交者想要的。 NOFOLLOW_LINKS 选项抑制符号链接的解析...即不会发生 user11171 批评的 getCanonicalPath() 的副作用。
  • 这可行,但 toRealPath 可能会在不同时间为同一文件返回不同的结果。例如。直接重命名磁盘上的文件后,它仍可能返回旧值。我在 Windows 上体验过。
【解决方案3】:
/**
 * Maps lower case strings to their case insensitive File
 */
private static final Map<String, File> insensitiveFileHandlerCache = new HashMap<String, File>();

/**
 * Case insensitive file handler. Cannot return <code>null</code>
 */
public static File newFile(String path) {
    if (path == null)
        return new File(path);
    path = path.toLowerCase();
    // First see if it is cached
    if (insensitiveFileHandlerCache.containsKey(path)) {
        return insensitiveFileHandlerCache.get(path);
    } else {
        // If it is not cached, cache it (the path is lower case)
        File file = new File(path);
        insensitiveFileHandlerCache.put(path, file);

        // If the file does not exist, look for the real path
        if (!file.exists()) {

            // get the directory
            String parentPath = file.getParent();
            if (parentPath == null) {
                // No parent directory? -> Just return the file since we can't find the real path
                return file;
            }

            // Find the real path of the parent directory recursively
            File dir = Util.newFile(parentPath);

            File[] files = dir.listFiles();
            if (files == null) {
                // If it is not a directory
                insensitiveFileHandlerCache.put(path, file);
                return file;
            }

            // Loop through the directory and put everything you find into the cache
            for (File otherFile : files) {
                // the path of our file will be updated at this point
                insensitiveFileHandlerCache.put(otherFile.getPath().toLowerCase(), otherFile);
            }

            // if you found what was needed, return it
            if (insensitiveFileHandlerCache.containsKey(path)) {
                return insensitiveFileHandlerCache.get(path);
            } 
        }
        // Did not find it? Return the file with the original path
        return file;
    }
}

使用

File file = newFile(path);

而不是

File file = new File(path);

它有缓存支持,所以它不应该太慢。进行了几次测试运行,它似乎工作。它递归地检查父目录以查看它们是否有正确的字母大小写。然后它为每个目录列出所有文件并缓存它们正确的字母大小写。最后,它检查是否找到了带有路径的文件并返回带有区分大小写路径的文件。

【讨论】:

    猜你喜欢
    • 2012-12-01
    • 2013-03-06
    • 2020-02-18
    • 2016-11-24
    • 2019-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多