简体   繁体   中英

Get file case-sensitive name, with case-insensitive spelling

I am making an application where the user picks a file from:

FilePicker.PickFile(filename)

where filename is a string.

In the method, it will translate into:

File file = new File(filename);

and nothing is wrong with that. Next, I do,

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

and this is where the problem begins. I want to get the name of the file, say "HELLO.txt," but if filename is "hello.txt," it still passes the file.exists() check, and file.getName() returns as "hello.txt," not "HELLO.txt". Is there a way, to return file.getName() as the case-sensitive version as "HELLO.txt?" Thanks!

An example:

HELLO.txt is the real file

FilePicker.PickFile("hello.txt");

OUTPUT:

hello.txt

When you are using Windows, which is case preserving (FAT32/NTFS/..), you can use file.getCanonicalFile() .getName() to get the canonical name of the selected file.

When you are using Linux or Android and you want to select a file based on a file name that does not necessarily match case, iterate through all files in the file's directory ( file.getParent() ), and pick the one that .equalsIgnoreCase the filename . Or see Case-insensitive File.equals on case-sensitive file system

/**
 * 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;
    }
}

Use

File file = newFile(path);

instead of

File file = new File(path);

It's backed by a cache so it shouldn't be too slow. Did a few test runs and it seems to work. It recursively checks the the parent directories to see if they do have the correct letter cases. Then it lists for each directory all files and caches their correct letter casing. In the end it checks if the file with the path has been found and returns the file with the case sensitive path.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM