非常快的文件列表限制

时间:2017-11-24 10:54:14

标签: c# .net filelist

我正在使用下面的代码,该代码使用Win32调用来获取目录的超快文件列表。它很快但有一些限制。

1)它不处理很长的路径。将找不到Windows 260字符路径限制以下的任何文件。 下面的潜在答案

2)此文件列表不会进入如下所示的快捷文件夹。

enter image description here

在保持操作速度的同时还有这些限制吗?

private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr FindFirstFileW(string lpFileName, out WIN32_FIND_DATAW lpFindFileData);

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

[DllImport("kernel32.dll")]
private static extern bool FindClose(IntPtr hFindFile);

private static bool FindNextFilePInvokeRecursive(string path, out List<FileInformation> files,
    out List<DirectoryInformation> directories)
{
    var fileList = new List<FileInformation>();
    var directoryList = new List<DirectoryInformation>();
    var findHandle = INVALID_HANDLE_VALUE;
    //var info = new List<Tuple<string, DateTime>>();
    try
    {
        findHandle = FindFirstFileW(path + @"\*", out var findData);
        if (findHandle != INVALID_HANDLE_VALUE)
            do
            {
                // Skip current directory and parent directory symbols that are returned.
                if (findData.cFileName != "." && findData.cFileName != "..")
                {
                    var fullPath = path + @"\" + findData.cFileName;
                    // Check if this is a directory and not a symbolic link since symbolic links could lead to repeated files and folders as well as infinite loops.
                    if (findData.dwFileAttributes.HasFlag(FileAttributes.Directory) &&
                        !findData.dwFileAttributes.HasFlag(FileAttributes.ReparsePoint))
                    {
                        directoryList.Add(new DirectoryInformation {FullPath = fullPath});
                        var subDirectoryFileList = new List<FileInformation>();
                        var subDirectoryDirectoryList = new List<DirectoryInformation>();
                        if (FindNextFilePInvokeRecursive(fullPath, out subDirectoryFileList,
                            out subDirectoryDirectoryList))
                        {
                            fileList.AddRange(subDirectoryFileList);
                            directoryList.AddRange(subDirectoryDirectoryList);
                        }
                    }
                    else if (!findData.dwFileAttributes.HasFlag(FileAttributes.Directory))
                    {
                        fileList.Add(new FileInformation {FullPath = fullPath});
                    }
                }
            } while (FindNextFile(findHandle, out findData));
    }
    catch (Exception exception)
    {
        Console.WriteLine("Caught exception while trying to enumerate a directory. {0}", exception);
        if (findHandle != INVALID_HANDLE_VALUE) FindClose(findHandle);
        files = null;
        directories = null;
        return false;
    }
    if (findHandle != INVALID_HANDLE_VALUE) FindClose(findHandle);
    files = fileList;
    directories = directoryList;
    return true;
}

private static List<FileInformation> FindNextFilePInvokeRecursiveParalleled(string path)
{
    List<FileInformation> files;
    var fileList = new List<FileInformation>();
    var fileListLock = new object();
    var directoryList = new List<DirectoryInformation>();
    var directoryListLock = new object();
    var findHandle = INVALID_HANDLE_VALUE;
    //var info = new List<Tuple<string, DateTime>>();
    try
    {
        path = path.EndsWith(@"\") ? path : path + @"\";
        findHandle = FindFirstFileW(path + @"*", out var findData);
        if (findHandle != INVALID_HANDLE_VALUE)
        {
            do
            {
                // Skip current directory and parent directory symbols that are returned.
                if (findData.cFileName != "." && findData.cFileName != "..")
                {
                    var fullPath = path + findData.cFileName;
                    // Check if this is a directory and not a symbolic link since symbolic links could lead to repeated files and folders as well as infinite loops.
                    if (findData.dwFileAttributes.HasFlag(FileAttributes.Directory) &&
                        !findData.dwFileAttributes.HasFlag(FileAttributes.ReparsePoint))
                        directoryList.Add(new DirectoryInformation {FullPath = fullPath});
                    else if (!findData.dwFileAttributes.HasFlag(FileAttributes.Directory))
                        fileList.Add(new FileInformation {FullPath = fullPath});
                }
            } while (FindNextFile(findHandle, out findData));
            directoryList.AsParallel().ForAll(x =>
            {
                var subDirectoryFileList = new List<FileInformation>();
                var subDirectoryDirectoryList = new List<DirectoryInformation>();
                if (FindNextFilePInvokeRecursive(x.FullPath, out subDirectoryFileList,
                    out subDirectoryDirectoryList))
                {
                    lock (fileListLock)
                    {
                        fileList.AddRange(subDirectoryFileList);
                    }
                    lock (directoryListLock)
                    {
                        directoryList.AddRange(subDirectoryDirectoryList);
                    }
                }
            });
        }
    }
    catch (Exception exception)
    {
        Console.WriteLine("Caught exception while trying to enumerate a directory. {0}", exception);
        if (findHandle != INVALID_HANDLE_VALUE) FindClose(findHandle);
        files = null;
        //directories = null;
        return null;
    }
    if (findHandle != INVALID_HANDLE_VALUE) FindClose(findHandle);
    files = fileList;
    //directories = directoryList;
    return files;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct WIN32_FIND_DATAW
{
    public readonly FileAttributes dwFileAttributes;
    internal readonly FILETIME ftCreationTime;
    internal readonly FILETIME ftLastAccessTime;
    internal readonly FILETIME ftLastWriteTime;
    private readonly int nFileSizeHigh;
    private readonly int nFileSizeLow;
    private readonly int dwReserved0;
    private readonly int dwReserved1;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public readonly string cFileName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public readonly string cAlternateFileName;
}

private class FileInformation
{
    public string FullPath;
    //public DateTime LastWriteTime;
}

private class DirectoryInformation
{
    public string FullPath;
    //public DateTime LastWriteTime;
}

解决方案1 ​​ 通过将窗口长路径前缀(\\?\)附加到用户输入的路径上,它似乎可以在文件路径中进一步搜索!尚未对此进行全面测试,但在初步测试中工作!! Link

现在我想我只需要问题2的解决方案。

0 个答案:

没有答案