Как обработать исключение, когда Directory.GetFiles() генерирует исключение, когда находит имя файла, которое ему не "нравится"?

На компьютере под управлением Vista с допустимым путем C:\Users\David при вызове Directory.GetFiles(@"C:\Users\David") выдается следующее исключение ArgumentException при запуске от имени пользователя David, который может просматривать содержимое каталога просто нормально в проводнике Windows:

System.ArgumentException message: Illegal characters in path.
Argument: ""
Stack trace:
   at System.IO.Path.CheckInvalidPathChars(String path)
   at System.IO.Path.InternalCombine(String path1, String path2)
   at System.IO.Directory.InternalGetFileDirectoryNames(String path, String userPathOriginal, String searchPattern, Boolean includeFiles, Boolean includeDirs, SearchOption searchOption)
   at System.IO.Directory.GetFiles(String path, String searchPattern, SearchOption searchOption)
   at System.IO.Directory.GetFiles(String path)
   at Microsoft.Samples.XFileExplorer.ContentView.CreateContentDataTable(String CurrentFolder) in C:\Users\david\Downloads\MEF Preview 5\MEF Preview 5\Samples\XFileExplorer\XFileExplorer\ContentView.xaml.cs:line 108

К компьютеру с Vista, возможно, обращался Mac с MacFuse, поэтому каталог содержит файл, который выглядит так, как будто он называется "._Icon", но на самом деле должен содержать некоторые недопустимые символы. Я считаю, что это источник ошибки. Я остаюсь с проблемой того, что делать, когда Directory.GetFiles() выдает исключение, когда он сталкивается с именем файла, которое ему не нравится? Существуют ли альтернативные способы составления списка содержимого файлов, которые не проходят через такое исключение?

Что касается этого конкретного файла, я подозреваю, что имя файла должно содержать некоторые символы, не отображаемые Windows Explorer или командной строкой:

   C:\Users\david>dir ._Icon
   Volume in drive C is Bootcamp
   Volume Serial Number is XXXX-XXX

   Directory of C:\Users\david

   File Not Found

И наконец:

   C:\Users\david>dir ._Icon*
   Volume in drive C is Bootcamp
   Volume Serial Number is XXXX-XXX
   Directory of C:\Users\david

   05/25/2008  07:40 AM            43,296 ._Icon
           1 File(s)         43,296 bytes
           0 Dir(s)  58,950,623,232 bytes free

Глядя на файл через SMB, похоже, что файл на самом деле называется "._Icon?". Каждый раз, когда я пытаюсь удалить файл с Mac, файл, кажется, немедленно появляется снова.

4 ответа

Решение

Можете ли вы попробовать перечислить файл, используя PInvoke FindFirstFile- см. Здесь. Это вызывает проблемы simmillar?

Информация о файле будет возвращена в структуре WIN32 FIND DATA. Затем вы вызываете FindNextFile для каждого файла, пока он не возвращает 0. В структуре вы можете использовать член cFileName, чтобы получить имя файла. Проверьте, что там недействительно.

Моя точка зрения заключается в том, что это может вернуть информацию о файле, которую издает Directory.GetFiles.

Вот пример его использования:

public const int MAX_PATH = 260;
 public const int MAX_ALTERNATE = 14;

[StructLayout(LayoutKind.Sequential)]
    public struct FILETIME {
    public uint dwLowDateTime;
    public uint dwHighDateTime;
 }; 

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] 
public struct WIN32_FIND_DATA {
    public FileAttributes dwFileAttributes;
    public FILETIME ftCreationTime; 
    public FILETIME ftLastAccessTime; 
    public FILETIME ftLastWriteTime; 
    public int nFileSizeHigh;
    public int nFileSizeLow;
    public int dwReserved0;
    public int dwReserved1;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_PATH)] 
    public string cFileName; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_ALTERNATE)] 
    public string cAlternate; 
}

[DllImport("kernel32", CharSet=CharSet.Unicode)] 
public static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);

[DllImport("kernel32", CharSet=CharSet.Unicode)] 
public static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);

private long RecurseDirectory(string directory, int level, out int files, out int folders) {
    IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
    long size = 0;
    files = 0;
    folders = 0;
    Kernel32.WIN32_FIND_DATA findData;

    IntPtr findHandle;

    // please note that the following line won't work if you try this on a network folder, like \\Machine\C$
    // simply remove the \\?\ part in this case or use \\?\UNC\ prefix
    findHandle = Kernel32.FindFirstFile(@"\\?\" + directory + @"\*", out findData);
    if (findHandle != INVALID_HANDLE_VALUE) {

        do {
            if ((findData.dwFileAttributes & FileAttributes.Directory) != 0) {

                if (findData.cFileName != "." && findData.cFileName != "..") {
                    folders++;

                    int subfiles, subfolders;
                    string subdirectory = directory + (directory.EndsWith(@"\") ? "" : @"\") + 
                        findData.cFileName;
                    if (level != 0)  // allows -1 to do complete search.
                        {
                    size += RecurseDirectory(subdirectory, level - 1, out subfiles, out subfolders);

                    folders += subfolders;
                    files += subfiles;
                    }
                }
            }
            else {
                // File
                files++;

                size += (long)findData.nFileSizeLow + (long)findData.nFileSizeHigh * 4294967296;
            }
        } 
        while (Kernel32.FindNextFile(findHandle, out findData));
        Kernel32.FindClose(findHandle);

    }

    return size;
}

// [Sample by Kåre Smith] // [Minor edits by Mike Liddell]

Просто к вашему сведению... то, что вы видите, это Resource Fork. Они сильно отличаются от ресурсов Windows и примерно аналогичны альтернативным потокам данных NTFS.

http://en.wikipedia.org/wiki/Resource_fork

Разветвление ресурса реализовано во всех файловых системах, используемых для системных дисков Macintosh (MFS, HFS и HFS Plus). Наличие ветки ресурса позволяет легко хранить различную дополнительную информацию, например, позволяя системе отображать правильный значок для файла и открывать его без необходимости расширения файла в имени файла. Хотя доступ к вилке данных работает так же, как и доступ к файлам в любой другой операционной системе - выберите файл, выберите смещение байта, прочитайте некоторые данные - доступ к вилке ресурса работает больше как извлечение структурированных записей из базы данных.

С сайта Microsoft sysinternals:

Файловая система NTFS предоставляет приложениям возможность создавать альтернативные потоки данных. По умолчанию все данные хранятся в основном безымянном потоке данных файла, но с помощью синтаксиса "file:stream" вы можете читать и записывать в альтернативы. Не все приложения написаны для доступа к альтернативным потокам, но вы можете продемонстрировать потоки очень просто. Сначала перейдите в каталог на диске NTFS из командной строки. Далее введите "echo hello > test:stream". Вы только что создали поток с именем 'stream', который связан с файлом 'test'. Обратите внимание, что когда вы смотрите на размер теста, он отображается как 0, и файл открывается пустым при открытии в любом текстовом редакторе. Чтобы увидеть ваш поток, введите "more

Как насчет того, чтобы просто удалить файл или переименовать его?

Серьезно, случается ли это достаточно часто, так что стоит написать специальный код для "исправления"?

Я знаю, что это немного устарело, но у меня точно такая же проблема с доступом к файловой системе OSX из Windows. DotNet выдает мне ошибку "недопустимые имена файлов", и причиной является нулевой байт файла Mac с именем icon, но с квадратом в конце имени файла.

Мое решение состояло в том, чтобы использовать немного кода VB6 и объекта файловой системы interop.scripting для перечисления файлов таким образом.

FSO не суетится с этими нелегальными персонажами.

надеюсь, что это помогает кому-то.

Другие вопросы по тегам