Why does GetDirectoryName return null for C:\?

后端 未结 3 1639
野性不改
野性不改 2021-01-29 01:15

I just came across what seems like a weird design choice:

System.IO.Path.GetDirectoryName(@\"C:\\folder\\file.ext\")

returns \"C:\\folder\"

3条回答
  •  时光说笑
    2021-01-29 01:47

    OK, I know this question hasn't been touched in years, but no one has really answered the question of 'Why is this the case?', so I'm going to take a long winded crack at it.

    For the purposes of this explanation only, a path is a conceptual thing for Windows. For practical purposes there are only two types of paths.

    • Local Paths - Start with a drive letter, C:\Folder\File.ext
    • Remote Paths - Start with a Server and a Share, \Server\Share\Folder\File.ext

    I'm deliberately leaving out relative paths because all relative paths can be converted into a Full Path that is one of the above two.

    Consider the following code:

            var examplePaths = new[]
            {
                "C:\\Folder\\File.ext",
                "C:\\Folder\\",
                "C:\\Folder",
                "C:\\",
                "C:",
                "\\\\Server\\Share\\Folder\\File.ext",
                "\\\\Server\\Share\\Folder\\",
                "\\\\Server\\Share\\Folder",
                "\\\\Server\\Share\\",
                "\\\\Server\\Share",
                "\\\\Server\\",
                "\\\\Server",
                "\\\\",
            };
    
            foreach(var path in examplePaths)
            {
                var result = Path.GetDirectoryName(path) ?? "NULL";
                Console.WriteLine($"'{path}'\t'{result}'");
            }
    

    If you run this, there is what I think, an interesting pattern:

     C:\Folder\File.ext                C:\Folder
     C:\Folder\                        C:\Folder 
     C:\Folder                         C:\ 
     C:\                               NULL 
     C:                                NULL 
     \\Server\Share\Folder\File.ext    \\Server\Share\Folder 
     \\Server\Share\Folder\            \\Server\Share\Folder 
     \\Server\Share\Folder             \\Server\Share 
     \\Server\Share\                   \\Server\Share 
     \\Server\Share                    NULL 
     \\Server\                         NULL 
     \\Server                          NULL 
     \\                                NULL 
    

    Lets talk about what a path is conceptually. First All the way to the left, is the path root. C:\ is a root. \Server\Share is a root. (Have a look at GetRootLength source code to see how it determines what part of the path is the root.)

    Looking at the above table, we see that everything that returned a null was either a root path all by itself or something less than a root.

    We can map things out conceptually:

     C:\Folder\File.ext                Root\Directory\Filename
     C:\Folder\                        Root\Directory\ 
     C:\Folder                         Root\Directory
     C:\                               Root\ 
     C:                                Root 
     \\Server\Share\Folder\File.ext    Root\Directory\Filename
     \\Server\Share\Folder\            Root\Directory\ 
     \\Server\Share\Folder             Root\Directory
     \\Server\Share\                   Root\ 
     \\Server\Share                    Root 
     \\Server\                         Root 
     \\Server                          Root 
     \\                                Root 
    

    What I am getting at is that C: and \Server\Share are both roots. And the '\' characters in \Server\Share have special meaning to that root. You can't naively just return whatever is left of the last '\' character.

    If you look at the GetDirectoryName source, you can can see that they take this into account, by requiring the variable i be greater than the root length.

    while (i > root && path[--i] != DirectorySeparatorChar && path[i] != AltDirectorySeparatorChar);
    

    So if you pass this function a path like 'C:\' the path parameter is a root all on its own.

    Now, maybe its not the best function name, but what GetDirectoryName might reasonably be thought of as 'Get the the directory that contains this file (or directory)' and when you think about it that way it suddenly make sense. Maybe GetParentDirectory would have been a better name.

    Get the directory that contains C:\Folder\file.ext, The obvious result is C:\Folder.

    Get the directory that contains C:\Folder, The result is the Root Directory on C:\ contains Folder.

    Get the directory that contains C:\ and the the answer has to be NULL/nothing because the root directory has no parent.

提交回复
热议问题