.NET Як перевірити, чи шлях є файлом, а не каталогом?


76

У мене є шлях, і мені потрібно визначити, це каталог або файл.

Це найкращий спосіб визначити, чи шлях є файлом?

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

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

Для каталогу я б змінив логіку.

string directory = @"C:\Test";

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

Якщо обох не існує, то я не піду робити жодну гілку. Тож припустимо, що вони обидва існують.



Відповіді:


117

Використання:

System.IO.File.GetAttributes(string path)

і перевірте, чи FileAttributesмістить повернутий результат значення FileAttributes.Directory:

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

15
Просто переконайтеся, що ви робите це за допомогою try / catch, оскільки шлях може навіть не існувати.
Л.Бушкін

Що станеться, якщо на шляху є символи підстановки? Я отримую незаконний аргумент символу, але що, якщо я використовую символи підстановки, і це законний шлях для моїх користувачів?
Michael Sheely

1
@MichaelSheely - AFAIK, щоб мати справу з узагальнюючими знаками, вам потрібно зателефонувати Directory.GetFilesза допомогою рядка і подивитися, чи не має результат результат більше нуля. "Шлях із узагальнюючими знаками" - це не шлях . Це шаблон .
ToolmakerSteve

55

Я думаю, що це найпростіший спосіб, коли вам потрібні лише дві перевірки:

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
}

Я не підтримав вас, але прийнята відповідь, безумовно, "простіша" і потребує лише одного дзвінка (а не двох).
Крістіан.

9
Перевага цього підходу полягає в тому, що він працює, навіть якщо у файловій системі взагалі немає відповідного запису (іншими словами, він не є ні папкою, ні файлом); У цьому сенсі це "простіше". До речі, ОП сказав "шлях", а не "шлях, який, як відомо, існує".
Тао

6
Так, я насправді думаю, що це краща відповідь, коли ви не впевнені, що шлях, який ви досліджуєте, є чи ні. Не турбуватися про ловлення винятків - це велика справа.
Бен Коллінз,

1
Я згоден, що цей метод ефективний. Я щойно створив крихітну утиліту, щоб визначити, чи вказане ім’я є файлом чи каталогом, і цей метод надзвичайно спростив повернення 1для каталогу, 2для файлу та 0помилок (наприклад, ім’я недійсне). Інструмент є мініатюрним (джерело 338 байт, зібрано 3584 байта) і працює дуже швидко.
Synetech

1
@TomPadilla: Що саме ти міг би очікувати, якщо шлях не існує?
Dirk Vollmar

11

Ви можете зробити це за допомогою коду взаємодії:

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

Для подальшого роз'яснення деяких коментарів ...

Введення некерованого коду в цьому не є не більш небезпечним для себе, ніж будь-який інший виклик файлу або вводу / виводу в .NET, оскільки всі вони ультимативно викликають некерований код.

Це один виклик функції із використанням рядка. Ви не вводите нових типів даних та / або використання пам'яті, викликаючи цю функцію. Так, вам потрібно покластися на некерований код для належного очищення, але, зрештою, ви маєте таку залежність від більшості викликів, пов’язаних з введенням / виведенням.

Для довідки, ось код File.GetAttributes (шлях до рядка) від 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;
}

Як бачите, він також звертається до некерованого коду, щоб отримати атрибути файлу, тому аргументи щодо введення некерованого коду як небезпечного є недійсними. Так само аргумент про те, щоб повністю залишатися в керованому коді. Для цього немає керованої реалізації коду. Навіть виклик File.GetAttributes (), як пропонують інші відповіді, має ті самі "проблеми" виклику некерованого коду, і я вважаю, що це найнадійніший спосіб визначити, чи є шлях каталогом.

Редагувати Щоб відповісти на коментар @Christian K щодо CAS. Я вважаю, що єдина причина, чому GetAttributes вимагає безпеки, полягає в тому, що йому потрібно прочитати властивості файлу, тому він хоче переконатися, що телефонний код має дозвіл на це. Це не те саме, що базові перевірки ОС (якщо такі є). Ви завжди можете створити функцію обгортки навколо виклику P / Invoke до PathIsDirectory, яка також вимагає певних дозволів CAS, якщо це необхідно.


3
Це здається великою роботою, щоб з’ясувати, чи є шлях файлом або каталогом.
Девід Басараб

2
Я не розумію, чому це голосування проти, хоча було б набагато простіше залишатися в керованому коді, використовуючи лише функціональність .NET.
Dirk Vollmar

1
Представляємо некерований код, щоб дізнатися, якщо шлях є файлом або каталогом, є небезпечним. Мені доводиться використовувати функцію виклику, щоб належним чином очистити пам’ять, інакше мій код може мати витоки.
Девід Басараб

1
Я досі не можу зрозуміти, чому це стає проти, оскільки воно правильно відповідає на питання методом, що не забезпечує рівня двозначності.
Скотт Дорман,

4
Ось у чому „краса” SO, навіть добрі відповіді можуть бути прихильниками деяких фанатиків;)
Wodzu

7

Припускаючи, що каталог існує ...

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

Якщо шлях не існує, GetAttributes поверне -1.
Binary Worrier

1
Документи, здається, вказують, що він видасть виняток, якщо файл не існує. msdn.microsoft.com/en-us/library/…
tvanfosson

4

Заціни:

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

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


2

Прочитайте атрибути файлу:

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

Перевірте прапор Каталогу .


1

Враховуючи, що певний рядок шляху не може представляти як каталог, так і файл, то наступне працює чудово і відкриває двері для інших операцій.

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

Якщо ви працюєте з файловою системою, використання FileInfoта DirectoryInfoнабагато простіше, ніж використання рядків.


Дивіться відповідь 0xA3, дещо кращі дзвінки imo.
nawfal

Або просто якщо (Directory.Exists (src)) ... Якщо це файл, він буде помилковим. Якщо src - це каталог, він буде помилковим. Якщо src - це каталог, який не існує, то за визначенням src не може мати каталог.
Кріс Бордеман

-3

Хм, схоже, Filesклас (in java.nio) насправді має статичний isDirectoryметод. Отже, я думаю, ви могли б насправді використовувати наступне:

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

4
Шукаємо рішення .NET.
Девід Басараб
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.