区分大小写的 Directory.Exists / File.Exists

Posted

技术标签:

【中文标题】区分大小写的 Directory.Exists / File.Exists【英文标题】:Case sensitive Directory.Exists / File.Exists 【发布时间】:2013-04-17 12:28:47 【问题描述】:

有没有办法区分大小写 Directory.Exists / File.Existssince

Directory.Exists(folderPath)

Directory.Exists(folderPath.ToLower())

都返回true?

大多数时候没关系,但我使用的宏如果路径不是 100% 匹配大小写,则该宏似乎不起作用。

【问题讨论】:

MSDN 明确指出:“路径参数不区分大小写。”,见msdn.microsoft.com/en-us/library/… 我知道,这就是我问的原因...... 【参考方案1】:

由于 Directory.Exists 使用不区分大小写的FindFirstFile,所以不。但是您可以将 PInvoke FindFirstFileEx 的附加标志参数设置为 FIND_FIRST_EX_CASE_SENSITIVE

【讨论】:

对不起,可能是一个转储问题,但这适用于 C# 吗?您所有的引用都与 C++ confused 相关 是的,应该可以,您可以使用 P/Invoke 从 C# 调用 Win32,阅读 P/Invoke,然后查看 pinvoke.net 的链接 +1。 @theknut,PInvoke 链接为您详细介绍了如何使其可在 C#/其他 .Net 语言中调用。 我试过了,它对我的​​字符串不起作用。它是 D:\Dir1\dir2\Dir3(驱动器上的物理目录是 D:\Dir1\Dir2\Dir3)。当我尝试 FindFirstFile 时,它​​只会返回 Dir3。 FindFirstFileEx(bla, FINDEX_INFO_LEVELS.FindExInfoBasic, out findData, FINDEX_SEARCH_OPS.FindExSearchLimitToDirectories, IntPtr.Zero, FIND_FIRST_EX_CASE_SENSITIVE); this 有帮助吗?如果不发布您的代码,并会尝试一起解决。【参考方案2】:

试试这个功能:

public static bool FileExistsCaseSensitive(string filename)

    string name = Path.GetDirectoryName(filename);

    return name != null 
           && Array.Exists(Directory.GetFiles(name), s => s == Path.GetFullPath(filename));

更新:

如 cmets 中所述,这仅检查文件名中的大小写,而不是路径中的大小写。这是因为 GetFullPath 方法返回的不是带有原始 case 的 Windows 原始路径,而是来自参数的路径的副本。

例如:

GetFullPath("c:\TEST\file.txt") -> "c:\TEST\file.txt"
GetFullPath("c:\test\file.txt") -> "c:\test\file.txt"

我尝试过的所有方法都以相同的方式工作:Fileinfo、DirectoryInfo。

这是一个使用 kernel32.dll 方法的解决方案:

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern int GetLongPathName(
        string path,
        StringBuilder longPath,
        int longPathLength
        );

    /// <summary>
    /// Return true if file exists. Non case sensitive by default.
    /// </summary>
    /// <param name="filename"></param>
    /// <param name="caseSensitive"></param>
    /// <returns></returns>
    public static bool FileExists(string filename, bool caseSensitive = false)
    
        if (!File.Exists(filename))
        
            return false;
        

        if (!caseSensitive)
        
            return true;
        

        //check case
        StringBuilder longPath = new StringBuilder(255);
        GetLongPathName(Path.GetFullPath(filename), longPath, longPath.Capacity);

        string realPath = Path.GetDirectoryName(longPath.ToString());
        return Array.Exists(Directory.GetFiles(realPath), s => s == filename);
    

【讨论】:

它在这里工作:如果你有 'c:\temp\TEST.txt',FileExistsCaseSensitive(@"c:\temp\test.txt") 将返回 false 这对我有用。 (在windows平台测试) 这个问题是,它只对 文件名 区分大小写,而不是整个路径。例子:用c:\tEst\test.txtc:\test\test.txt测试方法,而Windows上的真实路径是:c:\Test\test.txt,都返回true。我除了两个都返回false(整个路径区分大小写)。 对。我只使用文件名部分。无论如何,我用一个完全有效的解决方案更新了答案。【参考方案3】:

基于this question的解决方案,我写了下面的代码,除了Windows驱动器盘符之外,整个路径都区分大小写:

 static void Main(string[] args)
    
        string file1 = @"D:\tESt\Test.txt";
        string file2 = @"d:\Test\test.txt";
        string file3 = @"d:\test\notexists.txt";

        bool exists1 = Case_Sensitive_File_Exists(file1);
        bool exists2 = Case_Sensitive_File_Exists(file2);
        bool exists3 = Case_Sensitive_File_Exists(file3);

        Console.WriteLine("\n\nPress any key...");
        Console.ReadKey();
    

   static bool Case_Sensitive_File_Exists(string filepath)
   
        string physicalPath = GetWindowsPhysicalPath(filepath);
        if (physicalPath == null) return false;
        if (filepath != physicalPath) return false;
        else return true;
   

我从the question 复制了GetWindowsPhysicalPath(string path) 的代码

  [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;
    

注意我发现这个函数的唯一问题是,驱动器号似乎总是小写。示例:Windows上的物理路径为:D:\Test\test.txtGetWindowsPhysicalPath(string path)函数返回d:\Test\test.txt

【讨论】:

我建议为 [ThreadStatic]StringBuilder _builder=new StringBuilder(255); 创建一个字段,从而避免为每个调用添加分配。实际上.. 消除分配将是一个比这更大的变化......嗯。【参考方案4】:

这里有一个相对简单的方法来检查一个目录是否真的以命名的方式存在。我需要这个,因为我有一个重命名文件夹的选项,它会先检查是否不会发生冲突。因此,例如,如果我想将文件夹“cars”重命名为“Cars”。

这真的很简单。如果系统报告该文件夹存在,那么我只需在父文件夹上调用 GetDirectories,并将目录名称作为通配符传递(因此正好返回 1 个结果)。一个简单的比较就能给我答案。

static public bool DirExistsMatchCase(string path)

    // If it definitely doesn't return false
    if (!Directory.Exists(path)) return false;

    // Figure out if the case (of the final part) is the same
    string thisDir = Path.GetFileName(path);
    string actualDir = Path.GetFileName(Directory.GetDirectories(Path.GetDirectoryName(path), thisDir)[0]);
    return thisDir == actualDir;

【讨论】:

【参考方案5】:

尝试这 2 个不需要使用 PInvoke 并返回可为空的布尔值 (bool?) 的更简单的选项。我不是学科专家,所以我知道这是否是最有效的代码,但它对我有用。

只需传入一个路径,如果结果为 null (HasValue = false) 则找不到匹配项,如果结果为 false 则完全匹配,否则如果为 true 则匹配不同大小写。

GetFiles、GetDirectories 和 GetDrives 方法都返回保存在文件系统中的确切大小写,因此您可以使用区分大小写的比较方法。

注意:对于路径是精确驱动器的情况(例如 @"C:\"),我必须使用稍微不同的方法。

using System.IO;
class MyFolderFileHelper 
    public static bool? FileExistsWithDifferentCase(string fileName)
    
        bool? result = null;
        if (File.Exists(fileName))
        
            result = false;
            string directory = Path.GetDirectoryName(fileName);
            string fileTitle = Path.GetFileName(fileName);
            string[] files = Directory.GetFiles(directory, fileTitle);
            if (String.Compare(files[0], fileName, false) != 0)
                result = true;                
        
        return result;
    

    public static bool? DirectoryExistsWithDifferentCase(string directoryName)
    
        bool? result = null;
        if (Directory.Exists(directoryName))
        
            result = false;
            directoryName = directoryName.TrimEnd(Path.DirectorySeparatorChar);

            int lastPathSeparatorIndex = directoryName.LastIndexOf(Path.DirectorySeparatorChar);
            if (lastPathSeparatorIndex >= 0)
                                   
                string baseDirectory = directoryName.Substring(lastPathSeparatorIndex + 1);
                string parentDirectory = directoryName.Substring(0, lastPathSeparatorIndex);

                string[] directories = Directory.GetDirectories(parentDirectory, baseDirectory);
                if (String.Compare(directories[0], directoryName, false) != 0)
                    result = true;
            
            else
            
                //if directory is a drive
                directoryName += Path.DirectorySeparatorChar.ToString();
                DriveInfo[] drives = DriveInfo.GetDrives();
                foreach(DriveInfo driveInfo in drives)
                
                    if (String.Compare(driveInfo.Name, directoryName, true) == 0)
                    
                        if (String.Compare(driveInfo.Name, directoryName, false) != 0)
                            result = true;
                        break;
                    
                

            
        
        return result;
    

【讨论】:

【参考方案6】:

如果文件的(相对或绝对)路径是:

string AssetPath = "...";

以下确保文件存在且大小写正确:

if(File.Exists(AssetPath) && Path.GetFullPath(AssetPath) == Directory.GetFiles(Path.GetDirectoryName(Path.GetFullPath(AssetPath)), Path.GetFileName(Path.GetFullPath(AssetPath))).Single())


享受吧!

【讨论】:

以上是关于区分大小写的 Directory.Exists / File.Exists的主要内容,如果未能解决你的问题,请参考以下文章

在Directory.Delete Directory.Exists有时返回true?

Directory.Exists - 访问被拒绝 C# 的 UNC 路径

文件系统路径和 Directory.Exists()

Directory.Exists 用于 ASP.NET 中的网络路径

Test-Path / System.IO.Directory::Exists 未按预期工作

C# 获取文件大小