如果Directory.GetFiles()在找到不喜欢的文件名时抛出异常,如何处理异常?

时间:2009-05-27 14:39:05

标签: .net exception windows-vista macfuse

在具有有效路径C:\ Users \ David的Vista计算机上,调用Directory.GetFiles(@“C:\ Users \ David”)在以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机器碰巧是由运行MacFuse的Mac访问的,因此该目录包含一个看起来像名为“._Icon”的文件,但必须包含一些非法字符。我相信这是错误的根源。当Directory.GetFiles()在它不喜欢的文件名运行时抛出异常时,我留下了该怎么办的问题?是否有其他方法可以列出不通过此类例外的文件内容?

对于此特定文件,我怀疑文件名必须包含Windows资源管理器或命令提示符未显示的某些字符:

   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 个答案:

答案 0 :(得分:1)

您可以尝试使用PInvoke FindFirstFile - see here列出该文件。是否导致了相似问题?

文件信息将在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]

答案 1 :(得分:1)

只是一个FYI ......你所看到的是资源叉。这些与Windows资源有很大不同,大致类似于NTFS备用数据流。

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

  

资源分支在Macintosh(MFS,HFS和HFS Plus)上用于系统驱动器的所有文件系统中实现。资源分支的存在使得存储各种附加信息变得容易,例如允许系统显示文件的正确图标并打开它而无需文件名中的文件扩展名。虽然访问数据分支的工作方式类似于任何其他操作系统上的文件访问 - 选择文件,选择字节偏移量,读取一些数据 - 对资源分支的访问更像是从数据库中提取结构化记录。

来自Microsoft sysinternals网站:

  

NTFS文件系统为应用程序提供了创建备用数据信息流的能力。默认情况下,所有数据都存储在文件的主要未命名数据流中,但通过使用语法“file:stream”,您可以读取和写入备用数据。并非所有应用程序都是为了访问备用流而编写的,但您可以非常简单地演示流。首先,从命令提示符下更改到NTFS驱动器上的目录。接下来,输入'echo hello>测试:流”。您刚刚创建了一个名为'stream'的流,该流与文件'test'相关联。请注意,当您查看测试的大小时,它会报告为0,并且在任何文本编辑器中打开时该文件看起来都是空的。要查看您的信息流,请输入'more< test:stream'(类型命令不接受流语法,所以你必须使用更多)。

答案 2 :(得分:0)

如何删除文件或重命名?

说真的,这种情况经常发生,你是否值得编写特殊情况代码来“修复”?

答案 3 :(得分:0)

我知道这有点过时但我刚从Windows访问OSX文件系统时遇到了同样的问题。 DotNet给出了'非法文件名'错误,原因是名为icon的零字节Mac文件,但文件名末尾有一个正方形。

我的解决方案是使用一些VB6代码和interop.scripting filesystemobject来列出那些文件。

FSO不会废除这些非法字符。

希望能有所帮助。