3

在具有有效路径 C:\Users\David 的 Vista 机器上,调用 Directory.GetFiles(@"C:\Users\David") 以 David 用户身份运行时会引发以下 ArgumentException,后者可以查看目录的内容在 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

4 回答 4

1

您可以尝试使用 PInvoke FindFirstFile列出文件吗?请参见此处。是否会导致类似的问题?

文件信息将在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]
于 2009-05-28T11:28:48.573 回答
1

仅供参考……您所看到的是资源叉。这些与 Windows 资源有很大不同,大致类似于 NTFS 备用数据流。

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

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

从 Microsoft sysinternals 站点:

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

于 2010-08-02T18:51:08.850 回答
0

删除文件或重命名文件怎么样?

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

于 2009-05-27T14:41:54.953 回答
0

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

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

FSO 不会使用这些非法字符。

希望对某人有所帮助。

于 2010-11-01T02:24:40.287 回答