我正在使用下面的代码,该代码使用Win32调用来获取目录的超快文件列表。它很快但有一些限制。
1)它不处理很长的路径。将找不到Windows 260字符路径限制以下的任何文件。 下面的潜在答案
2)此文件列表不会进入如下所示的快捷文件夹。
在保持操作速度的同时还有这些限制吗?
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的解决方案。