#c_sharp #net #winapi #файловая_система
Надо сканировать огромное количество файлов и папок. Обычно для этого используется метод Directory.EnumerateFileSystemEntries. Возможно ли как-то ускорить процесс чтения файловой системы?
Ответы
Ответ 1
Можно ускорить почти в два раза, если использовать WinAPI. // Microsoft (R) Roslyn C# Compiler version 1.1.0.51204 using System.Runtime.InteropServices; [DllImport("kernel32.dll")] static extern int GetLastError(); [DllImport("kernel32.dll")] static extern bool FindClose(IntPtr handle); class SafeHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid { private SafeHandle() : base(true) { } protected override bool ReleaseHandle() { return FindClose(this.handle); } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] struct DATA { // WIN32_FIND_DATA public FileAttributes FileAttributes; public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime; public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime; public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime; public uint FileSizeHigh; public uint FileSizeLow; public uint Reserved0; public uint Reserved1; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string FileName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public string AlternateFileName; } [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern SafeHandle FindFirstFileEx(string name, int i, out DATA data, int so, IntPtr sf, int f); [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern bool FindNextFile(SafeHandle h, out DATA data); IEnumerable ReadPath(string path) { // например: "c:\" | "c:\*.png" | "c:\*" DATA d; var p = String.Concat(@"\\?\", path.TrimEnd('\\', ' ')); using (var h = FindFirstFileEx(p, 1, out d, 0, IntPtr.Zero, 2)) { if (h.IsInvalid) throw new System.ComponentModel.Win32Exception(GetLastError()); yield return d; while (FindNextFile(h, out d)) if (d.FileName != "..") yield return d; var e = GetLastError(); // e = 18 -- дошли до конца if (e != 18) throw new System.ComponentModel.Win32Exception(e); } } Получить файлы и папки в c:\: foreach (var d in ReadPath(@"c:\*")) Console.WriteLine("name=" + d.FileName); Получить файлы в c:\temp\ и подпапках: class File { public string Path; public string Name; } IEnumerableScan(string path) { foreach (var d in ReadPath(path + "*").Skip(1)) { // сканируем только подпапки, а junction пропускаем if ((d.FileAttributes & FileAttributes.Directory) != 0 && (d.FileAttributes & FileAttributes.ReparsePoint) == 0) foreach (var f in Scan(path + d.FileName + "\\")) yield return f; else yield return new File { Path = path, Name = d.FileName }; } } long ToLong(uint high, uint low) { return (long)(((UInt64)high << 0x20) | (UInt64)low); } foreach (var f in Scan(@"c:\temp\")) Console.WriteLine( f.Path + "\t\t\t" + f.Name + " size=" + ToLong(d.FileSizeHigh, d.FileSizeLow)); Ответ 2
Нужно индексировать FS в базу данных и работать потом с базой.
Комментариев нет:
Отправить комментарий