我想和这个问题完全一样:
Windows文件系统不区分大小写.如果给定一个文件/文件夹名称(例如"somefile"),我得到该文件/文件夹的实际名称(例如,如果Explorer显示它,它应该返回"SomeFile")?
但我需要在.NET中完成它,我想要完整的路径(D:/Temp/Foobar.xml
而不仅仅是Foobar.xml
).
我看到FullName
在FileInfo
课堂上没有做到这一点.
我似乎因为NTFS不区分大小写,所以无论名称是否正确,它都将始终正确接受您的输入.
获取正确路径名的唯一方法似乎是找到像John Sibly建议的文件.
我创建了一个方法,它将获取路径(文件夹或文件)并返回它的正确套件版本(对于整个路径):
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(); } }
以下是一些适用于我的机器的测试用例:
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(); }
如果文件不存在,该方法将返回提供的值.
可能有更快的方法(这使用递归),但我不确定是否有任何明显的方法来做到这一点.
我喜欢Yona的回答,但我希望它:
支持UNC路径
告诉我路径是否不存在
使用迭代而不是递归(因为它只使用尾递归)
最小化对Path.Combine的调用次数(以最小化字符串连接).
////// Gets the exact case used on the file system for an existing file or directory. /// /// A relative or absolute path. /// The full path using the correct case if the path exists. Otherwise, null. ///True if the exact path was found. False otherwise. ////// This supports drive-lettered paths and UNC paths, but a UNC root /// will be returned in title case (e.g., \\Server\Share). /// public static bool TryGetExactPath(string path, out string exactPath) { bool result = false; exactPath = null; // DirectoryInfo accepts either a file path or a directory path, and most of its properties work for either. // However, its Exists property only works for a directory path. DirectoryInfo directory = new DirectoryInfo(path); if (File.Exists(path) || directory.Exists) { Listparts = new List (); DirectoryInfo parentDirectory = directory.Parent; while (parentDirectory != null) { FileSystemInfo entry = parentDirectory.EnumerateFileSystemInfos(directory.Name).First(); parts.Add(entry.Name); directory = parentDirectory; parentDirectory = directory.Parent; } // Handle the root part (i.e., drive letter or UNC \\server\share). string root = directory.FullName; if (root.Contains(':')) { root = root.ToUpper(); } else { string[] rootParts = root.Split('\\'); root = string.Join("\\", rootParts.Select(part => CultureInfo.CurrentCulture.TextInfo.ToTitleCase(part))); } parts.Add(root); parts.Reverse(); exactPath = Path.Combine(parts.ToArray()); result = true; } return result; }
对于UNC路径,这会出现标题情况下的根(\\ Server\Share),而不是确切的情况,因为尝试确定远程服务器的确切案例名称和共享的确切案例名称会有很多工作.如果您对添加该支持感兴趣,则需要使用P/Invoke方法,如NetServerEnum和NetShareEnum.但这些可能很慢,并且它们不支持对服务器进行预先过滤并共享您关注的名称.
这是TryGetExactPath的单元测试方法(使用Visual Studio Testing Extensions):
[TestMethod] public void TryGetExactPathNameTest() { string machineName = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(Environment.MachineName.ToLower()); string[] testPaths = new[] { @"C:\Users\Public\desktop.ini", @"C:\pagefile.sys", @"C:\Windows\System32\cmd.exe", @"C:\Users\Default\NTUSER.DAT", @"C:\Program Files (x86)\Microsoft.NET\Primary Interop Assemblies", @"C:\Program Files (x86)", @"Does not exist", @"\\Nas\Main\Setups", @"\\Nas\Main\Setups\Microsoft\Visual Studio\VS 2015\vssdk_full.exe", @"\\" + machineName + @"\C$\Windows\System32\ActionCenter.dll", @"..", }; DictionaryexpectedExactPaths = new Dictionary () { { @"..", Path.GetDirectoryName(Environment.CurrentDirectory) }, }; foreach (string testPath in testPaths) { string lowercasePath = testPath.ToLower(); bool expected = File.Exists(lowercasePath) || Directory.Exists(lowercasePath); string exactPath; bool actual = FileUtility.TryGetExactPath(lowercasePath, out exactPath); actual.ShouldEqual(expected); if (actual) { string expectedExactPath; if (expectedExactPaths.TryGetValue(testPath, out expectedExactPath)) { exactPath.ShouldEqual(expectedExactPath); } else { exactPath.ShouldEqual(testPath); } } else { exactPath.ShouldBeNull(); } } }
受Ivan的回答启发,这里也是一种处理驱动器字母外壳的方法:
public string FixFilePathCasing(string filePath) { string fullFilePath = Path.GetFullPath(filePath); string fixedPath = ""; foreach(string token in fullFilePath.Split('\\')) { //first token should be drive token if(fixedPath == "") { //fix drive casing string drive = string.Concat(token, "\\"); drive = DriveInfo.GetDrives() .First(driveInfo => driveInfo.Name.Equals(drive, StringComparison.OrdinalIgnoreCase)).Name; fixedPath = drive; } else { fixedPath = Directory.GetFileSystemEntries(fixedPath, token).First(); } } return fixedPath; }