我需要知道哪条path是真正的path。
例如:
真正的path是:d:\ src \ File.txt
用户给我:D:\ src \ file.txt
我需要结果:d:\ src \ File.txt
你可以使用这个功能:
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)] static extern uint GetLongPathName(string ShortPath, StringBuilder sb, int buffer); [DllImport("kernel32.dll")] static extern uint GetShortPathName(string longpath, StringBuilder sb, int buffer); protected static string GetWindowsPhysicalPath(string path) { StringBuilder builder = new StringBuilder(255); // names with long extension can cause the short name to be actually larger than // the long name. GetShortPathName(path, builder, builder.Capacity); path = builder.ToString(); uint result = GetLongPathName(path, builder, builder.Capacity); if (result > 0 && result < builder.Capacity) { //Success retrieved long file name builder[0] = char.ToLower(builder[0]); return builder.ToString(0, (int)result); } if (result > 0) { //Need more capacity in the buffer //specified in the result variable builder = new StringBuilder((int)result); result = GetLongPathName(path, builder, builder.Capacity); builder[0] = char.ToLower(builder[0]); return builder.ToString(0, (int)result); } return null; }
作为一个老前辈,我总是使用FindFirstFile来达到这个目的。 .Net翻译是:
Directory.GetFiles(Path.GetDirectoryName(userSuppliedName), Path.GetFileName(userSuppliedName)).FirstOrDefault();
这只会得到你的路径的文件名部分正确的外壳,而不是整个路径。
JeffreyLWhitledge的评论提供了一个链接到递归版本,可以工作(虽然不总是)来解决完整的路径。
获取文件的实际路径的方法(这不适用于文件夹)是遵循以下步骤:
CreateFileMapping
为该文件创建一个映射。 GetMappedFileName
来获取文件的名称。 QueryDosDevice
将其转换为MS-DOS样式的路径名称。 如果你想编写一个更强大的程序,也可以使用目录(但更多的痛苦和一些无证的功能),请按照下列步骤操作:
CreateFile
或NtOpenFile
获取文件/文件夹的NtOpenFile
。 NtQueryObject
来获取完整的路径名称。 FileNameInformation
调用NtQueryInformationFile
以获取相对于卷的路径。 \Device\HarddiskVolume1\Hello.txt
,第二个路径为\Hello.txt
,则您现在知道该卷的路径为\Device\HarddiskVolume1
。 QueryDosDevice
将替换整个NT样式路径的卷部分与驱动器QueryDosDevice
进行转换。 现在你有了真正的文件路径。
由于Borja的答案不适用于禁用8.3名称的卷,这里是Tergiver建议的递归实现(适用于文件和文件夹,以及UNC共享的文件和文件夹,但不在其计算机名称和共享名称上)。
不存在的文件或文件夹没有问题,存在的是验证和纠正,但您可能会遇到文件夹重定向问题,例如,当试图获得“C:\ WinDoWs \ sYsteM32 \ driVErs \ eTC \主机”的正确路径您将在64位Windows上获得“C:\ Windows \ System32 \ drivers \ eTC \ hosts”,因为没有包含“C:\ Windows \ sysWOW64 \ drivers”的“etc”文件夹。
测试场景:
Directory.CreateDirectory(@"C:\Temp\SomeFolder"); File.WriteAllLines(@"C:\Temp\SomeFolder\MyTextFile.txt", new String[] { "Line1", "Line2" });
用法:
FileInfo myInfo = new FileInfo(@"C:\TEMP\SOMEfolder\MyTeXtFiLe.TxT"); String myResult = myInfo.GetFullNameWithCorrectCase(); //Returns "C:\Temp\SomeFolder\MyTextFile.txt"
码:
public static class FileSystemInfoExt { public static String GetFullNameWithCorrectCase(this FileSystemInfo fileOrFolder) { //Check whether null to simulate instance method behavior if (Object.ReferenceEquals(fileOrFolder, null)) throw new NullReferenceException(); //Initialize common variables String myResult = GetCorrectCaseOfParentFolder(fileOrFolder.FullName); return myResult; } private static String GetCorrectCaseOfParentFolder(String fileOrFolder) { String myParentFolder = Path.GetDirectoryName(fileOrFolder); String myChildName = Path.GetFileName(fileOrFolder); if (Object.ReferenceEquals(myParentFolder, null)) return fileOrFolder.TrimEnd(new char[]{Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }); if (Directory.Exists(myParentFolder)) { //myParentFolder = GetLongPathName.Invoke(myFullName); String myFileOrFolder = Directory.GetFileSystemEntries(myParentFolder, myChildName).FirstOrDefault(); if (!Object.ReferenceEquals(myFileOrFolder, null)) { myChildName = Path.GetFileName(myFileOrFolder); } } return GetCorrectCaseOfParentFolder(myParentFolder) + Path.DirectorySeparatorChar + myChildName; } }
这是一个备用解决方案,适用于文件和目录。 使用GetFinalPathNameByHandle,根据文档,仅支持Vista / server2008或更高版本的桌面应用程序。
请注意,如果给出一个符号链接,它将解析符号链接,这是查找“最终”路径的一部分。
// http://www.pinvoke.net/default.aspx/shell32/GetFinalPathNameByHandle.html [DllImport("coreel32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern uint GetFinalPathNameByHandle(SafeFileHandle hFile, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpszFilePath, uint cchFilePath, uint dwFlags); private const uint FILE_NAME_NORMALIZED = 0x0; static string GetFinalPathNameByHandle(SafeFileHandle fileHandle) { StringBuilder outPath = new StringBuilder(1024); var size = GetFinalPathNameByHandle(fileHandle, outPath, (uint)outPath.Capacity, FILE_NAME_NORMALIZED); if (size == 0 || size > outPath.Capacity) throw new Win32Exception(Marshal.GetLastWin32Error()); // may be prefixed with \\?\, which we don't want if (outPath[0] == '\\' && outPath[1] == '\\' && outPath[2] == '?' && outPath[3] == '\\') return outPath.ToString(4, outPath.Length - 4); return outPath.ToString(); } // http://www.pinvoke.net/default.aspx/kernel32.createfile [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern SafeFileHandle CreateFile( [MarshalAs(UnmanagedType.LPTStr)] string filename, [MarshalAs(UnmanagedType.U4)] FileAccess access, [MarshalAs(UnmanagedType.U4)] FileShare share, IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, [MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes, IntPtr templateFile); private const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000; public static string GetFinalPathName(string dirtyPath) { // use 0 for access so we can avoid error on our metadata-only query (see dwDesiredAccess docs on CreateFile) // use FILE_FLAG_BACKUP_SEMANTICS for attributes so we can operate on directories (see Directories in remarks section for CreateFile docs) using (var directoryHandle = CreateFile( dirtyPath, 0, FileShare.ReadWrite | FileShare.Delete, IntPtr.Zero, FileMode.Open, (FileAttributes)FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero)) { if (directoryHandle.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error()); return GetFinalPathNameByHandle(directoryHandle); } }
在Windows上,路径不区分大小写。 所以两条路都是同样真实的。
如果你想得到某种具有规范大小写的路径(即Windows如何认为它应该被大写),你可以调用FindFirstFile()和路径作为掩码,然后取出找到的文件的全名。 如果路径无效,那么你将不会得到一个规范的名字,天生的。