我需要知道哪条是给定路径的真实路径。
例如:
真正的路径是:d:\ src \ File.txt
并且用户给我:D:\ src \ file.txt
结果我需要:d:\ src \ File.txt
答案 0 :(得分:17)
您可以使用此功能:
[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;
}
答案 1 :(得分:8)
作为一个老朋友,我总是为此目的使用FindFirstFile。 .Net翻译是:
Directory.GetFiles(Path.GetDirectoryName(userSuppliedName), Path.GetFileName(userSuppliedName)).FirstOrDefault();
这只能获得路径文件名部分的正确大小,而不是整个路径。
JeffreyLWhitledge的评论提供了一个递归版本的链接,该版本可以解决完整路径(但并非总是如此)。
答案 2 :(得分:3)
获取文件的实际路径(这对文件夹不起作用)的方法是按照以下步骤操作:
CreateFileMapping
为文件创建映射。GetMappedFileName
获取文件名称。QueryDosDevice
将其转换为MS-DOS样式的路径名。如果您想编写一个更强大的程序,该程序也适用于目录(但更多的痛苦和一些未记录的功能),请按照下列步骤操作:
CreateFile
或NtOpenFile
。NtQueryObject
以获取完整路径名称。NtQueryInformationFile
致电FileNameInformation
以获取音量相对路径。\Device\HarddiskVolume1\Hello.txt
而第二条路径获得\Hello.txt
,则您现在知道该路径的路径为\Device\HarddiskVolume1
。QueryDosDevice
转换替换完整NT样式路径的卷部分和驱动器号。现在您拥有该文件的真实路径。
答案 3 :(得分:1)
由于Borja的答案不适用于禁用8.3名称的卷,这里是Tergiver建议的递归实现(适用于文件和文件夹,以及UNC共享的文件和文件夹,但不适用于其机器名称及其共享名)。
不存在的文件或文件夹没有问题,存在的内容经过验证和纠正,但是您可能会遇到文件夹重定向问题,例如在尝试获取“C:\ WinDoWs \ sYsteM32 \ drivers \ eTC”的正确路径时\主机“你会在64位Windows上获得”C:\ Windows \ System32 \ drivers \ eTC \ hosts“,因为没有”etc“文件夹包含”C:\ Windows \ sysWOW64 \ drivers“。
测试场景:
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;
}
}
答案 4 :(得分:1)
替代解决方案
这是一个解决方案,可以让我使用区分大小写的路径在Windows和服务器之间移动文件。它沿着目录树向下走,并使用GetFileSystemEntries()
更正每个条目。如果路径的一部分无效(UNC或文件夹名称),则它仅在该点之前更正路径,然后使用原始路径找到它无法找到的路径。无论如何,希望这会在处理同一问题时节省其他时间。
private string GetCaseSensitivePath(string path)
{
var root = Path.GetPathRoot(path);
try
{
foreach (var name in path.Substring(root.Length).Split(Path.DirectorySeparatorChar))
root = Directory.GetFileSystemEntries(root, name).First();
}
catch (Exception e)
{
// Log("Path not found: " + path);
root += path.Substring(root.Length);
}
return root;
}
答案 5 :(得分:0)
这是一个替代解决方案,适用于文件和目录。使用GetFinalPathNameByHandle,仅根据文档支持Vista / Server2008或更高版本上的桌面应用程序。
请注意,如果你给它一个,它将解析一个符号链接,这是找到&#34; final&#34;路径。
// http://www.pinvoke.net/default.aspx/shell32/GetFinalPathNameByHandle.html
[DllImport("Kernel32.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);
}
}
答案 6 :(得分:0)
我试图避免dll导入,所以对我来说最好的方法是使用System.Linq和System.IO.Directory类。
以您为例 实际路径是:d:\ src \ File.txt 用户给我:D:\ src \ file.txt
此代码:
使用System.Linq;
public static class PathUtils
{
public static string RealPath(string inputPath)
{
return Directory.GetFiles(Path.GetDirectoryName(inputPath))
.FirstOrDefault(p => String.Equals(Path.GetFileName(p),
Path.GetFileName(inputPath), StringComparison.OrdinalIgnoreCase));
}
}
var p = PathUtils.RealPath(@“ D:\ src \ file.txt”);
方法应返回路径“ d:\ src \ File.txt”或“ D:\ src \ File.txt”。
答案 7 :(得分:-3)
在Windows上,路径不区分大小写。所以这两条路径都同样真实。
如果你想获得一些规范大写的路径(即Windows认为它应该大写),你可以用路径作为掩码调用FindFirstFile(),然后获取找到的文件的全名。如果路径无效,那么您将无法获得规范名称。