Case sensitive Directory.Exists / File.Exists

梦想与她 提交于 2019-12-23 07:16:16

问题


Is there a way to have a case sensitive Directory.Exists / File.Existssince

Directory.Exists(folderPath)

and

Directory.Exists(folderPath.ToLower())

both return true?

Most of the time it doesn't matter but I'm using a macro which seems not to work if the path doesn't match cases 100%.


回答1:


Since Directory.Exists uses FindFirstFile which is not case-sensitive, no. But you can PInvoke FindFirstFileEx with an additionalFlags parameter set to FIND_FIRST_EX_CASE_SENSITIVE




回答2:


Based on the solution of this question, I wrote the code below which is case sensitive for the whole path except the Windows Drive letter:

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

I copied the code for GetWindowsPhysicalPath(string path) from the question

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

Note the only problem I found with this function is, the drive letter seems to be always in lowercase. Example: The physical path on Windows is: D:\Test\test.txt, the GetWindowsPhysicalPath(string path)function returns d:\Test\test.txt




回答3:


Try this function:

public static bool FileExistsCaseSensitive(string filename)
{
    string name = Path.GetDirectoryName(filename);

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

Update:

As stated in comments, this only check cases in filename, not in the path. This is because GetFullPath method doesn't return the Windows original path with original cases, but a copy of the path from the parameter.

Ex:

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

All methods I tried work the same way: Fileinfo, DirectoryInfo.

Here is a solution using a kernel32.dll method:

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



回答4:


Try these 2 simpler options that do not need to use PInvoke and return a nullable Boolean (bool?). I am not a subject expert so I do know if this is the most efficient code but it works for me.

Simply pass in a path and if the result is null (HasValue = false) no match is found, if the result is false there is an exact match, otherwise if true there is a match with a difference case.

The methods GetFiles, GetDirectories and GetDrives all return the exact case as saved on your file system so you can use a case sensitive compare method.

NB: for the case where the path is an exact drive (e.g. @"C:\") I have to use a slightly different approach.

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



回答5:


If the (relative or absolute) path of your file is:

string AssetPath = "...";

The following ensures that the file both exists and has the correct casing:

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

Enjoy!



来源:https://stackoverflow.com/questions/16183788/case-sensitive-directory-exists-file-exists

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!