views:

2284

answers:

7

I have a path and I need to determine if it is a directory or file.

Is this the best way to determine if the path is a file?

string file = @"C:\Test\foo.txt";

bool isFile = !System.IO.Directory.Exists(file) && 
                         System.IO.File.Exists(file);

For a directory I would reverse the logic.

string directory = @"C:\Test";

bool isDirectory = System.IO.Directory.Exists(directory) && 
                            !System.IO.File.Exists(directory);

If both don't exists that then I won't go do either branch. So assume they both do exists.

A: 

You can do this with some interop code:

    [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
    [return: MarshalAsAttribute(UnmanagedType.Bool)]
    public static extern bool PathIsDirectory([MarshalAsAttribute(UnmanagedType.LPWStr), In] string pszPath);

To further clarify some of the comments...

Introducing unmanaged code in this is not any more inherintly dangerous than any of the other file or I/O related calls in .NET since they ultimatley all call in to unmanaged code.

This is a single function call using a string. You aren't introducing any new data types and/or memory usage by calling this function. Yes, you do need to rely on the unmanaged code to properly clean up, but you ultimately have that dependency on most of the I/O related calls.

For reference, here is the code to File.GetAttributes(string path) from Reflector:

public static FileAttributes GetAttributes(string path)
{
    string fullPathInternal = Path.GetFullPathInternal(path);
    new FileIOPermission(FileIOPermissionAccess.Read, new string[] { fullPathInternal }, false, false).Demand();
    Win32Native.WIN32_FILE_ATTRIBUTE_DATA data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
    int errorCode = FillAttributeInfo(fullPathInternal, ref data, false, true);
    if (errorCode != 0)
    {
        __Error.WinIOError(errorCode, fullPathInternal);
    }
    return (FileAttributes) data.fileAttributes;
}

As you can see, it is also calling in to unmanaged code in order to retrieve the file attributes, so the arguements about introducing unmanaged code being dangerous are invalid. Likewise, the argument about staying completely in managed code. There is no managed code implementation to do this. Even calling File.GetAttributes() as the other answers propose have the same "issues" of calling unmanged code and I believe this is the more reliable method to accomplish determining if a path is a directory.

Edit To answer the comment by @Christian K about CAS. I believe the only reason GetAttributes makes the security demand is because it needs to read the properties of the file so it wants to make sure the calling code has permission to do so. This is not the same as the underlying OS checks (if there are any). You can always create a wrapper function around the P/Invoke call to PathIsDirectory that also demands certain CAS permissions, if necessary.

Scott Dorman
That seems like allot of work to figure out if a path is a file or directory.
David Basarab
How is that a lot of work? You declare a single imported function and can then call it as if it were a native method.
Scott Dorman
I don't see why this is downvoted, although it would be much simpler to stay in managed code using .NET functionality only.
0xA3
Introducing Unmanaged code to get if a path is a file or directory is dangerous. I have to relay on the calling function to clean up the memory properly or my code could have leaks.
David Basarab
I didn't downvote just because it's unmanaged code, I down voted because it's not part of the standard .net library
Alnitak
@Alnitak: The question never specified that he wanted only managed code, besides there really is no way to do it using only managed code.
Scott Dorman
I'm not sure if that is an issue, but the GetAttributes() does CAS using FileIOPermission, the native call does not (appart from the operating system checks, which are not neccessarly the same, are they?).
Christian.K
I still fail to see why this is getting downvoted as it correctly answers the question with a method that provides no level of ambiguitity.
Scott Dorman
That is the "beauty" of SO, even a good answers might be downvoted by some zealots ;)
Wodzu
+24  A: 

Use:

System.IO.File.GetAttributes(string path)

and check whether the returned FileAttributes result contains the value FileAttributes.Directory:

bool isDir = (File.GetAttributes(path) & FileAttributes.Directory)
                 == FileAttributes.Directory;
Alnitak
Gollum
Just make sure you do this in a try/catch, since the path may not even exist.
LBushkin
+5  A: 

Assuming the directory exists...

bool isDir = (File.GetAttributes(path) & FileAttributes.Directory)
                  == FileAttributes.Directory;
tvanfosson
If path doesn't exist, GetAttributes will return -1.
Binary Worrier
Docs seem to indicate that it will throw an exception if the file doesn't exist. http://msdn.microsoft.com/en-us/library/system.io.file.getattributes.aspx
tvanfosson
your test is the wrong way around - that should be isDir not isFile...
Alnitak
corrected to isDir
0xA3
+2  A: 

Check this out:

/// <summary>
/// Returns true if the given file path is a folder.
/// </summary>
/// <param name="Path">File path</param>
/// <returns>True if a folder</returns>
public bool IsFolder(string path)
{
    return ((File.GetAttributes(path) & FileAttributes.Directory) == FileAttributes.Directory);
}

from http://www.jonasjohn.de/snippets/csharp/is-folder.htm

Dror
+1  A: 

Read the file attributes:

FileAttributes att = System.IO.File.GetAttributes(PATH_TO_FILE);

Check for the Directory flag.

Igor Zelaya
A: 

Given that a particular path string cannot represent both a directory and a file, then the following works just fine and opens the door for other operations.

bool isFile = new FileInfo(path).Exists;
bool isDir = new DirectoryInfo(path).Exists;

If you're working with the file system, using FileInfo and DirectoryInfo is much simpler than using strings.

Drew Noakes
+1  A: 

I think this is the simplest way where you only need two checks:

        string file = @"C:\tmp";
        if (System.IO.Directory.Exists(file))
        {
            // do stuff when file is an existing directory
        }
        else if (System.IO.File.Exists(file))
        {
            // do stuff when file is an existing file
        }
0xA3
I did not downvote you, but it the accepted answer is surely "simpler" and only needs one call (not two).
Christian.K
Well, it depends, I personally would consider isDir = System.IO.Directory.Exists(file) to be "simpler" than the accepted solution.
0xA3