Подтвердить что ты не робот

Определение наличия файла с использованием С# и разрешения пути UNC

Я пытаюсь написать функцию, чтобы определить, существует ли файл. Эти два метода возвращают несогласованные результаты (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

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

4b9b3361

Ответ 1

Вы можете создать 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 $".

Ответ 2

Смотрите этот вопрос:
как вы можете легко проверить, запрещен ли доступ к файлу в .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

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

Это:

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

против

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

Ответ 4

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

Ответ 5

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

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

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

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

Ответ 6

Изменить: Ну, я просто понял, что file.exists работает нормально. Это определенно было бы предпочтительным методом. Ниже код даст вам возможность пригласить пользователя к проверке подлинности, если доступ к ресурсу должен осуществляться под другой учетной записью домена. Может когда-нибудь помочь кому-нибудь, поэтому я просто оставлю код здесь.

Если вам нужно получить доступ к 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);

    }
}