Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在Windows上获取区分大小写的路径?_C#_.net_Filepath - Fatal编程技术网

C# 如何在Windows上获取区分大小写的路径?

C# 如何在Windows上获取区分大小写的路径?,c#,.net,filepath,C#,.net,Filepath,我需要知道给定路径的真实路径 例如: 实际路径是: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); [D

我需要知道给定路径的真实路径

例如:

实际路径是: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;
}
[DllImport(“kernel32.dll”,SetLastError=true,CharSet=CharSet.Auto)]
静态外部uint GetLongPathName(字符串短路径、StringBuilder sb、int缓冲区);
[DllImport(“kernel32.dll”)]
静态外部uint GetShortPathName(字符串长路径、StringBuilder sb、int缓冲区);
受保护的静态字符串GetWindowsPhysicalPath(字符串路径)
{
StringBuilder=新的StringBuilder(255);
//具有长扩展名的名称可能导致短名称实际大于
//长长的名字。
GetShortPathName(路径、生成器、生成器容量);
path=builder.ToString();
uint result=GetLongPathName(路径、生成器、builder.Capacity);
if(结果>0&&result0)
{
//缓冲区中需要更多的容量
//在结果变量中指定
生成器=新的StringBuilder((int)结果);
结果=GetLongPathName(路径、生成器、builder.Capacity);
生成器[0]=字符ToLower(生成器[0]);
返回builder.ToString(0,(int)结果);
}
返回null;
}

在Windows上,路径不区分大小写。所以这两条路都是同样真实的


如果您想获得某种具有规范大写形式的路径(即Windows认为应该如何大写),可以使用该路径作为掩码调用FindFirstFile(),然后获取找到的文件的全名。如果路径无效,则自然无法获得规范名称。

获取文件实际路径的方法(这对文件夹不起作用)是按照以下步骤操作:

  • 调用
    CreateFileMapping
    为文件创建映射
  • 调用
    GetMappedFileName
    获取文件名
  • 使用
    QueryDosDevice
    将其转换为MS DOS样式的路径名
  • 如果您想编写一个更健壮的程序,该程序也可以与目录一起使用(但会带来更多麻烦和一些未记录的功能),请执行以下步骤:

  • 使用
    CreateFile
    NtOpenFile
    获取文件/文件夹的句柄
  • 调用
    NtQueryObject
    获取完整路径名
  • 使用
    FileNameInformation
    调用
    NtQueryInformationFile
    ,以获取卷的相对路径
  • 使用上面的两个路径,获取代表卷本身的路径组件。例如,如果第一个路径为
    \Device\HarddiskVolume1\Hello.txt
    ,第二个路径为
    \Hello.txt
    ,则您现在知道卷的路径为
    \Device\HarddiskVolume1
  • 使用记录不良的Mount Manager I/O控制代码或
    QueryDosDevice
    转换,将完整NT样式路径的卷部分替换为驱动器号

  • 现在您有了文件的实际路径。

    作为一个老前辈,我总是使用FindFirstFile来实现这一目的。Net翻译为:

    Directory.GetFiles(Path.GetDirectoryName(userSuppliedName), Path.GetFileName(userSuppliedName)).FirstOrDefault();
    
    这只会为路径的文件名部分获得正确的大小写,而不是整个路径


    JeffreyLWhitledge的评论提供了一个指向递归版本的链接,该版本可以(尽管不总是)解析完整路径。

    由于Borja的答案不适用于禁用8.3名称的卷,这里是Tergiver建议的递归实现(适用于文件和文件夹以及UNC共享的文件和文件夹,但不适用于其计算机名或共享名)

    不存在的文件或文件夹没有问题,存在的文件或文件夹已验证并更正,但您可能会遇到文件夹重定向问题,例如,当尝试获取“C:\WinDoWs\sYsteM32\driVErs\eTC\Hosts”的正确路径时,您将在64位WinDoWs上获得“C:\WinDoWs\sYsteM32\driVErs\eTC\Hosts”,因为没有带“eTC”的“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"
    
    代码:


    这里有一个替代解决方案,适用于文件和目录。使用GetFinalPathNameByHandle,根据文档,它仅支持Vista/Server2008或更高版本的桌面应用程序

    请注意,如果您给它一个符号链接,它将解析该符号链接,这是查找“最终”路径的一部分


    替代解决方案

    下面是一个解决方案,它使用区分大小写的路径在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;
    }
    

    我试图避免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”。

    我的印象是Windows有一个基本上不区分大小写的文件系统。在这种情况下,这充其量是不必要的,最坏的情况是……胡说八道。)@djacobson:你错了。Windows基本上是区分大小写的,但某些标志使它的行为不区分大小写。有关详细信息,请搜索
    OBJ_case_INSENSITIVE
    。例如,如果你正在编写BASH emulator,那么你自然需要文件的正确大小写。我需要应用
    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;
    }
    
    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));
        }
    }