Определение наличия файла с использованием c # и определение пути UNC - PullRequest
27 голосов
/ 19 января 2009

Я пытаюсь написать функцию, чтобы определить, существует ли файл. Два метода, как оказалось, возвращают противоречивые результаты (кажется, что fileExists () обеспечивает точные результаты по сравнению с isFileFound (), который возвращает ложные срабатывания - я бы ожидал исключение при попытке создать экземпляр).

protected bool isFileFound(string path, string fileName)
    {
        System.IO.FileInfo fi = null;

        bool found = false;
        try
        {
            fi = new System.IO.FileInfo(path + fileName);
            found = true;
        }
        catch (Exception e)
        {
            baselogger.Fatal(e.Message + " " + e.StackTrace + " \n" + path + fileName);
        }

        return found;
    }

    protected bool fileExists(string path, string pattern)
    {
        bool success = false;

        try
        {
            success = File.Exists(path + pattern);
        }
        catch (Exception e)
        {
            baselogger.Warn(e.Message + " " + e.StackTrace + " " + e.Source);
        }

        return success;
    }

Похоже, ни один из них не может разрешить UNC-путь следующего синтаксиса: \\ abcserver \ c $ \ xyzfolder \ foo.bar

Любая идея, почему путь unc не работает для этих методов, будет принята с благодарностью.

Ответы [ 6 ]

37 голосов
/ 19 января 2009

Вы можете создать FileInfo для несуществующего файла. Но затем вы можете проверить свойство FileInfo.Exists, чтобы определить, существует ли файл, например:

FileInfo fi = new FileInfo(somePath);
bool exists = fi.Exists;

Обновление : В коротком тесте это также работало для путей UNC, например, как это:

FileInfo fi = new FileInfo(@"\\server\share\file.txt");
bool exists = fi.Exists;

Вы уверены, что учетная запись (под которой запущено ваше приложение) имеет доступ к общему ресурсу? Я думаю, что (по умолчанию) административные права требуются для доступа к общему ресурсу "c $".

13 голосов
/ 19 января 2009

см. Этот вопрос:
как можно легко проверить, запрещен ли доступ к файлу в .NET?

Короткая версия этого вопроса такова, что вы этого не сделаете, потому что файловая система нестабильна. Просто попробуйте открыть файл и перехватить исключение в случае сбоя.

Причина, по которой ваш метод isFileFound не работает, заключается в том, что используемая вами структура FileInfo также может использоваться для создания файлов. Вы можете создать объект FileInfo с необходимой информацией для несуществующего файла, вызвать его метод .Create(), и вы сразу установили нужные свойства.

Я подозреваю, что причиной сбоя пути UNC является либо 1) проблема с правами доступа к общему ресурсу администратора от пользователя, запустившего ваше приложение, или 2) Символ $ вызывает метод либо потому что он вводится неправильно или из-за ошибки в базовой реализации .Exists ().

Обновление:

Когда я публикую это предложение, я почти всегда получаю жалобу на выполнение исключений. Давай поговорим об этом. Да, обработка исключений стоит дорого: очень дорого. Есть несколько вещей, которые вы можете сделать в программировании, которые медленнее. Но вы знаете, что это за эти несколько вещей? Дисковый и сетевой ввод / вывод. Вот ссылка, показывающая, сколько стоит дисковый ввод-вывод и сетевой ввод-вывод:

https://gist.github.com/jboner/2841832

Latency Comparison Numbers
--------------------------
L1 cache reference                            0.5 ns
Branch mispredict                             5   ns
L2 cache reference                            7   ns             14x L1 cache
Mutex lock/unlock                            25   ns
Main memory reference                       100   ns             20x L2 cache, 200x L1 cache
Compress 1K bytes with Zippy              3,000   ns
Send 1K bytes over 1 Gbps network        10,000   ns    0.01 ms
Read 4K randomly from SSD*              150,000   ns    0.15 ms
Read 1 MB sequentially from memory      250,000   ns    0.25 ms
Round trip within same datacenter       500,000   ns    0.5  ms
Read 1 MB sequentially from SSD*      1,000,000   ns    1    ms  4X memory
Disk seek                            10,000,000   ns   10    ms  20x datacenter roundtrip
Read 1 MB sequentially from disk     20,000,000   ns   20    ms  80x memory, 20X SSD
Send packet CA->Netherlands->CA     150,000,000   ns  150    ms

Если думать в наносекундах не ваше дело, вот еще одна ссылка, которая нормализует один цикл ЦП как 1 секунду и масштабируется оттуда:

http://blog.codinghorror.com/the-infinite-space-between-words/

1 CPU cycle             0.3 ns      1 s
Level 1 cache access    0.9 ns      3 s
Level 2 cache access    2.8 ns      9 s
Level 3 cache access    12.9 ns     43 s
Main memory access      120 ns      6 min
Solid-state disk I/O    50-150 μs   2-6 days
Rotational disk I/O     1-10 ms     1-12 months
Internet: SF to NYC     40 ms       4 years
Internet: SF to UK      81 ms       8 years
Internet: SF to AUS     183 ms      19 years
OS virt. reboot         4 s         423 years
SCSI command time-out   30 s        3000 years
Hardware virt. reboot   40 s        4000 years
Physical system reboot  5 m         32 millenia

Принимая даже самый лучший сценарий для исключений, вы можете получить доступ к памяти как минимум 480 раз, ожидая первого ответа от диска, и это предполагает очень быстрый SSD. Многим из нас все еще нужны вращающиеся жесткие диски, где дела идут намного хуже.

И это только начало истории. Когда вы используете .Exists(), вы берете на себя эту дополнительную стоимость (и это дополнение: вам придется делать ту же самую работу снова, когда вы открываете файл) при каждой попытке , Вы оплачиваете эту стоимость независимо от того, существует файл или нет, потому что диск все равно должен искать его в своих файловых таблицах. При использовании метода исключения вы оплачиваете только дополнительную стоимость разматывания стека вызовов в случае сбоя.

Другими словами, да: исключения ужасно дороги. Но по сравнению с проверкой диска она все же быстрее: и не с небольшим отрывом. К счастью, это вряд ли повлияет на общую производительность вашего приложения ... но я все же хочу уложить аргумент "исключения являются медленными" для этой конкретной задачи.

3 голосов
/ 19 января 2009

Это может иметь место, а может и нет, но не могли бы вы присоединить к своему пути неверное имя файла для одного из ваших случаев.

Это:

success = File.Exists (путь + шаблон);

против

success = File.Exists (Path.Join (путь, шаблон));

1 голос
/ 03 ноября 2010

Редактировать: Ну, я только что понял, что file.exists работает нормально. Это определенно будет предпочтительным методом. Приведенный ниже код даст вам возможность заставить Windows запрашивать у пользователя аутентификацию, если общий ресурс должен быть доступен под другой учетной записью домена. Возможно, когда-нибудь кто-нибудь поможет, поэтому я просто оставлю здесь код.

Если вам нужен доступ к UNC-пути или общему ресурсу администратора с использованием других учетных данных: MSDN

Для загрузки WNetAddConnection2 используйте этот код:

using System;
using System.Runtime.InteropServices;

namespace Win32Api
{
    public enum ResourceScope
    {
        RESOURCE_CONNECTED = 1,
        RESOURCE_GLOBALNET,
        RESOURCE_REMEMBERED,
        RESOURCE_RECENT,
        RESOURCE_CONTEXT
    };

    public enum ResourceType
    {
        RESOURCETYPE_ANY,
        RESOURCETYPE_DISK,
        RESOURCETYPE_PRINT,
        RESOURCETYPE_RESERVED = 8
    };

    [Flags]
    public enum ResourceUsage
    {
        RESOURCEUSAGE_CONNECTABLE = 0x00000001,
        RESOURCEUSAGE_CONTAINER = 0x00000002,
        RESOURCEUSAGE_NOLOCALDEVICE = 0x00000004,
        RESOURCEUSAGE_SIBLING = 0x00000008,
        RESOURCEUSAGE_ATTACHED = 0x00000010,
        RESOURCEUSAGE_ALL = (RESOURCEUSAGE_CONNECTABLE |
                             RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED),
    };

    public enum ResourceDisplayType
    {
        RESOURCEDISPLAYTYPE_GENERIC,
        RESOURCEDISPLAYTYPE_DOMAIN,
        RESOURCEDISPLAYTYPE_SERVER,
        RESOURCEDISPLAYTYPE_SHARE,
        RESOURCEDISPLAYTYPE_FILE,
        RESOURCEDISPLAYTYPE_GROUP,
        RESOURCEDISPLAYTYPE_NETWORK,
        RESOURCEDISPLAYTYPE_ROOT,
        RESOURCEDISPLAYTYPE_SHAREADMIN,
        RESOURCEDISPLAYTYPE_DIRECTORY,
        RESOURCEDISPLAYTYPE_TREE,
        RESOURCEDISPLAYTYPE_NDSCONTAINER
    };

    [StructLayout(LayoutKind.Sequential)]
    public class NetResource
    {
        public ResourceScope Scope;
        public ResourceType Type;
        public ResourceDisplayType DisplayType;
        public ResourceUsage Usage;
        public string LocalName;
        public string RemoteName;
        public string Comment;
        public string Provider;
    };

    [Flags]
    public enum AddConnectionOptions
    {
        CONNECT_UPDATE_PROFILE = 0x00000001,
        CONNECT_UPDATE_RECENT = 0x00000002,
        CONNECT_TEMPORARY = 0x00000004,
        CONNECT_INTERACTIVE = 0x00000008,
        CONNECT_PROMPT = 0x00000010,
        CONNECT_NEED_DRIVE = 0x00000020,
        CONNECT_REFCOUNT = 0x00000040,
        CONNECT_REDIRECT = 0x00000080,
        CONNECT_LOCALDRIVE = 0x00000100,
        CONNECT_CURRENT_MEDIA = 0x00000200,
        CONNECT_DEFERRED = 0x00000400,
        CONNECT_RESERVED = unchecked((int)0xFF000000),
        CONNECT_COMMANDLINE = 0x00000800,
        CONNECT_CMD_SAVECRED = 0x00001000,
        CONNECT_CRED_RESET = 0x00002000
    }

    public static class NativeMethods
    {
        [DllImport("mpr.dll", EntryPoint = "WNetAddConnection2")]
        public static extern int WNetAddConnection2(
            NetResource netResource, string password,
            string username, AddConnectionOptions options);

        [DllImport("mpr.dll")]
        public static extern int WNetCancelConnection2(string name, int flags,
        bool force);

    }
}
1 голос
/ 19 января 2009

Итак, я пошел с

bool success = File.Exists(path + Filename);

, в отличие от использования маршрута FileInfo.

Спасибо за все предложения!

1 голос
/ 19 января 2009

Это может помочь вам:
http://www.codeplex.com/FileDirectoryPath
Это NDepend.Helpers.FilePathDirectory , которые имеют «API проверки правильности пути» среди других, которые могут быть полезны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...