tags:

views:

206

answers:

4

I want to do exactly the same as in this question:

Windows file system is case insensitive. How, given a file/folder name (e.g. "somefile"), I get the actual name of that file/folder (e.g. it should return "SomeFile" if Explorer displays it so)?

But I need to do it in .NET and I want the full path (D:/Temp/Foobar.xml and not just Foobar.xml).

I see that FullName on the FileInfo class doesn't do the trick.

A: 

Have you tried the DirectoryInfo and Path class, they might do the trick. (Have not tried it myself)

Drejc
A: 

Interesting problem.

One way to do it is to "find" file based on the case insensitive name, and then look at the FileInfo.FullName property. I've tested this using the following function and it gives the required result.

static string GetCaseSensitiveFileName(string filePath)
{
    string caseSensitiveFilePath = null;

    DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(filePath));
    FileInfo[] files = dirInfo.GetFiles(Path.GetFileName(filePath));
    if (files.Length > 0)
    {
        caseSensitiveFilePath = files[0].FullName;
    }

    return caseSensitiveFilePath;
}

You need to be a bit careful here - if you have two files callled names like file.xml and File.xml then it would only return the first one.

John Sibly
The original question already stated that looking at FileInfo.FullName doesn't provide the required information.
Scott Dorman
That's correct - if you just use the FileInfo class then this is the case.But if you find the file again using DirectoryInfo and GetFiles (passing in the full path), then if you look at the FullPath you can back the required information. I've tested the function that I posted and it works.
John Sibly
You are correct, this does work and returns the correct information.
Scott Dorman
This does not fix the case on the directory name, but only the filename. Ie in "d:/temp/foobar.xml" only the "foobar.xml" bit will be fixed.
pauldoo
+1  A: 

I think the only way you are going to be able to do this is by using the same Win32 API, namely the SHGetFileInfo method, mentioned in the accepted answer for the question you reference. In order to do this, you will need to use some interop p/invoke calls. Take a look at pinvoke.net for an example of how to do this and what additional structs you will need.

Scott Dorman
+3  A: 

I seems that since NTFS is case insensitive it will always except your input correctly regardless if the name is cased right.

The only way to get the correct path name seems to find the file like John Sibly suggested.

I created a method that will take a path (folder or file) and return the correctly cased version of it: (for the entire path)

    public static string GetExactPathName(string pathName)
    {
        if (!(File.Exists(pathName) || Directory.Exists(pathName)))
            return pathName;

        var di = new DirectoryInfo(pathName);

        if (di.Parent != null) {
            return Path.Combine(
                GetExactPathName(di.Parent.FullName), 
                di.Parent.GetFileSystemInfos(di.Name)[0].Name);
        } else {
            return di.Name.ToUpper();
        }
    }

Here are some test cases that worked on my machine:

    static void Main(string[] args)
    {
        string file1 = @"c:\documents and settings\administrator\ntuser.dat";
        string file2 = @"c:\pagefile.sys";
        string file3 = @"c:\windows\system32\cmd.exe";
        string file4 = @"c:\program files\common files";
        string file5 = @"ddd";

        Console.WriteLine(GetExactPathName(file1));
        Console.WriteLine(GetExactPathName(file2));
        Console.WriteLine(GetExactPathName(file3));
        Console.WriteLine(GetExactPathName(file4));
        Console.WriteLine(GetExactPathName(file5));

        Console.ReadLine();
    }

The method will return the supplied value if the file does not exists.

There might be faster methods (this uses recursion) but I'm not sure if there are any obvious ways to do it.

Y Low