.NET Làm thế nào để kiểm tra xem đường dẫn có phải là tệp và không phải là thư mục hay không?


76

Tôi có một đường dẫn và tôi cần xác định xem đó là thư mục hay tệp.

Đây có phải là cách tốt nhất để xác định xem đường dẫn có phải là tệp không?

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

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

Đối với một thư mục, tôi sẽ đảo ngược logic.

string directory = @"C:\Test";

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

Nếu cả hai đều không tồn tại thì tôi sẽ không đi làm cả hai chi nhánh. Vì vậy, giả sử cả hai đều tồn tại.



Câu trả lời:


117

Sử dụng:

System.IO.File.GetAttributes(string path)

và kiểm tra xem FileAttributeskết quả trả về có chứa giá trị hay không FileAttributes.Directory:

bool isDir = (File.GetAttributes(path) & FileAttributes.Directory)
                 == FileAttributes.Directory;

15
Chỉ cần đảm bảo rằng bạn làm điều này trong một lần thử / bắt, vì đường dẫn thậm chí có thể không tồn tại.
LBushkin

Điều gì xảy ra nếu đường dẫn có ký tự đại diện trong đó? Tôi nhận được một đối số ký tự bất hợp pháp, nhưng điều gì sẽ xảy ra nếu tôi sử dụng các ký tự đại diện và đó là một đường dẫn hợp pháp cho người dùng của tôi?
Michael Sheely

1
@MichaelSheely - AFAIK, để xử lý các ký tự đại diện, bạn phải gọi Directory.GetFilesvới chuỗi và xem liệu kết quả có số đếm lớn hơn 0 hay không. "Đường dẫn có ký tự đại diện" không phải là đường dẫn . Đó là một khuôn mẫu .
ToolmakerSteve

55

Tôi nghĩ đây là cách đơn giản nhất mà bạn chỉ cần kiểm tra hai lần:

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
}

Tôi không phản đối bạn, nhưng câu trả lời được chấp nhận chắc chắn là "đơn giản hơn" và chỉ cần một cuộc gọi (không phải hai).
Christian.K

9
Ưu điểm của cách tiếp cận này là nó hoạt động ngay cả khi không có mục nhập phù hợp nào trong hệ thống tệp (nói cách khác, nó không phải là thư mục cũng không phải là tệp); Theo nghĩa đó, nó là "đơn giản hơn". Ngẫu nhiên, OP nói "một con đường", chứ không phải "một con đường được biết là tồn tại".
Tao

6
Vâng, tôi thực sự nghĩ rằng đây là câu trả lời tốt hơn khi bạn không chắc con đường mình đang điều tra có ở đó hay không. Không phải lo lắng về việc bắt các ngoại lệ là một vấn đề lớn.
Ben Collins

1
Tôi đồng ý rằng phương pháp này có hiệu quả. Tôi vừa tạo một tiện ích nhỏ để xác định xem tên được chỉ định là tệp hay thư mục và phương pháp này giúp việc trả về 1thư mục, 2tệp và 0lỗi cực kỳ đơn giản (ví dụ: tên không hợp lệ). Công cụ này rất nhỏ (338 byte nguồn, 3584 byte biên dịch) và chạy rất nhanh.
Synetech

1
@TomPadilla: Chính xác thì điều gì bạn sẽ mong đợi xảy ra nếu đường dẫn không tồn tại?
Dirk Vollmar

11

Bạn có thể làm điều này với một số mã tương tác:

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

Để làm rõ thêm một số ý kiến ​​...

Việc giới thiệu mã không được quản lý trong điều này không nguy hiểm hơn bất kỳ tệp tin kế thừa nào hoặc các lệnh gọi liên quan đến I / O khác trong .NET vì chúng tối hậu thư đều gọi đến mã không được quản lý.

Đây là một lệnh gọi hàm đơn sử dụng một chuỗi. Bạn sẽ không giới thiệu bất kỳ kiểu dữ liệu mới nào và / hoặc cách sử dụng bộ nhớ bằng cách gọi hàm này. Có, bạn cần phải dựa vào mã không được quản lý để dọn dẹp đúng cách, nhưng cuối cùng bạn phải phụ thuộc vào hầu hết các cuộc gọi liên quan đến I / O.

Để tham khảo, đây là mã đến File.GetAttributes (đường dẫn chuỗi) từ 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;
}

Như bạn có thể thấy, nó cũng đang gọi đến mã không được quản lý để truy xuất các thuộc tính tệp, vì vậy các tranh luận về việc đưa mã không được quản lý là nguy hiểm là không hợp lệ. Tương tự như vậy, tranh luận về việc hoàn toàn ở trong mã được quản lý. Không có triển khai mã được quản lý để làm điều này. Ngay cả việc gọi File.GetAttributes () như các câu trả lời khác đề xuất cũng có cùng "vấn đề" khi gọi mã không thay đổi và tôi tin rằng đây là phương pháp đáng tin cậy hơn để xác định xem đường dẫn có phải là một thư mục hay không.

Chỉnh sửa Để trả lời nhận xét của @Christian K về CAS. Tôi tin rằng lý do duy nhất GetAttributes tạo ra yêu cầu bảo mật là vì nó cần đọc các thuộc tính của tệp, vì vậy nó muốn đảm bảo rằng mã gọi có quyền làm như vậy. Điều này không giống như kiểm tra hệ điều hành cơ bản (nếu có). Bạn luôn có thể tạo một hàm bao bọc xung quanh lệnh gọi P / Invoke tới PathIsDirectory cũng yêu cầu một số quyền CAS nhất định, nếu cần.


3
Đó có vẻ như là tất cả công việc để tìm hiểu xem đường dẫn có phải là tệp hay thư mục hay không.
David Basarab

2
Tôi không hiểu tại sao điều này lại bị phản đối, mặc dù sẽ đơn giản hơn nhiều nếu chỉ sử dụng mã được quản lý bằng cách sử dụng chức năng .NET.
Dirk Vollmar

1
Giới thiệu mã Unmanaged để biết đường dẫn là tệp hoặc thư mục có nguy hiểm không. Tôi phải chuyển tiếp chức năng gọi để dọn dẹp bộ nhớ đúng cách nếu không mã của tôi có thể bị rò rỉ.
David Basarab

1
Tôi vẫn không hiểu tại sao điều này lại bị phản đối vì nó trả lời chính xác câu hỏi bằng một phương pháp không có mức độ mơ hồ.
Scott Dorman

4
Đó là "vẻ đẹp" của SO, thậm chí là một câu trả lời tốt có thể được downvoted bởi một số cuồng tín;)
Wodzu

7

Giả sử thư mục tồn tại ...

bool isDir = (File.GetAttributes(path) & FileAttributes.Directory)
                  == FileAttributes.Directory;

Nếu đường dẫn không tồn tại, GetAttributes sẽ trả về -1.
Binary Worrier

1
Các tài liệu dường như chỉ ra rằng nó sẽ ném ra một ngoại lệ nếu tệp không tồn tại. msdn.microsoft.com/en-us/library/…
tvanfosson

4

Kiểm tra cái này:

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

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


2

Đọc các thuộc tính tệp:

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

Kiểm tra cờ Thư mục .


1

Cho rằng một chuỗi đường dẫn cụ thể không thể đại diện cho cả thư mục tệp, thì cách sau hoạt động tốt và mở ra cánh cửa cho các hoạt động khác.

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

Nếu bạn đang làm việc với hệ thống tệp, việc sử dụng FileInfoDirectoryInfođơn giản hơn nhiều so với sử dụng chuỗi.


Xem câu trả lời của 0xA3, tốt hơn một chút gọi imo.
nawfal

Hoặc chỉ khi (Directory.Exists (src)) ... Nếu đó là một tệp, nó sẽ là sai. Nếu src là một thư mục, nó sẽ là false. Nếu src là một thư mục không tồn tại, thì theo định nghĩa src không thể là một thư mục.
Chris Bordeman,

-3

Hmm, có vẻ như Fileslớp (in java.nio) thực sự có một isDirectoryphương thức tĩnh . Vì vậy, tôi nghĩ rằng bạn thực sự có thể sử dụng như sau:

Path what = ...
boolean isDir = Files.isDirectory(what);

4
Tìm kiếm giải pháp .NET.
David Basarab
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.