温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何用C#代码实现快速查询文件

发布时间:2022-10-21 09:58:53 来源:亿速云 阅读:181 作者:iii 栏目:编程语言

这篇“如何用C#代码实现快速查询文件”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“如何用C#代码实现快速查询文件”文章吧。

相信使用过Everything的人都对其超快的搜索速度印象非常深刻,它的主要原理是通过扫描NTFS磁盘的USN Journal读取的文件列表,而不是磁盘目录,由于USN Journal非常小,因此能实现快速搜索。

由于.Net程序的Dll基本上是通用的,在C#中也可以直接使用它。

    public class MFTScanner     {         private static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);         private const uint GENERIC_READ = 0x80000000;         private const int FILE_SHARE_READ = 0x1;         private const int FILE_SHARE_WRITE = 0x2;         private const int OPEN_EXISTING = 3;         private const int FILE_READ_ATTRIBUTES = 0x80;         private const int FILE_NAME_IINFORMATION = 9;         private const int FILE_FLAG_BACKUP_SEMANTICS = 0x2000000;         private const int FILE_OPEN_FOR_BACKUP_INTENT = 0x4000;         private const int FILE_OPEN_BY_FILE_ID = 0x2000;         private const int FILE_OPEN = 0x1;         private const int OBJ_CASE_INSENSITIVE = 0x40;         private const int FSCTL_ENUM_USN_DATA = 0x900b3;         [StructLayout(LayoutKind.Sequential)]         private struct MFT_ENUM_DATA         {             public long StartFileReferenceNumber;             public long LowUsn;             public long HighUsn;         }         [StructLayout(LayoutKind.Sequential)]         private struct USN_RECORD         {             public int RecordLength;             public short MajorVersion;             public short MinorVersion;             public long FileReferenceNumber;             public long ParentFileReferenceNumber;             public long Usn;             public long TimeStamp;             public int Reason;             public int SourceInfo;             public int SecurityId;             public FileAttributes FileAttributes;             public short FileNameLength;             public short FileNameOffset;         }         [StructLayout(LayoutKind.Sequential)]         private struct IO_STATUS_BLOCK         {             public int Status;             public int Information;         }         [StructLayout(LayoutKind.Sequential)]         private struct UNICODE_STRING         {             public short Length;             public short MaximumLength;             public IntPtr Buffer;         }         [StructLayout(LayoutKind.Sequential)]         private struct OBJECT_ATTRIBUTES         {             public int Length;             public IntPtr RootDirectory;             public IntPtr ObjectName;             public int Attributes;             public int SecurityDescriptor;             public int SecurityQualityOfService;         }         //// MFT_ENUM_DATA         [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]         private static extern bool DeviceIoControl(IntPtr hDevice, int dwIoControlCode, ref MFT_ENUM_DATA lpInBuffer, int nInBufferSize, IntPtr lpOutBuffer, int nOutBufferSize, ref int lpBytesReturned, IntPtr lpOverlapped);         [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]         private static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, IntPtr lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);         [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]         private static extern Int32 CloseHandle(IntPtr lpObject);         [DllImport("ntdll.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]         private static extern int NtCreateFile(ref IntPtr FileHandle, int DesiredAccess, ref OBJECT_ATTRIBUTES ObjectAttributes, ref IO_STATUS_BLOCK IoStatusBlock, int AllocationSize, int FileAttribs, int SharedAccess, int CreationDisposition, int CreateOptions, int EaBuffer,         int EaLength);         [DllImport("ntdll.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]         private static extern int NtQueryInformationFile(IntPtr FileHandle, ref IO_STATUS_BLOCK IoStatusBlock, IntPtr FileInformation, int Length, int FileInformationClass);         private IntPtr m_hCJ;         private IntPtr m_Buffer;         private int m_BufferSize;         private string m_DriveLetter;         private class FSNode         {             public long FRN;             public long ParentFRN;             public string FileName;             public bool IsFile;             public FSNode(long lFRN, long lParentFSN, string sFileName, bool bIsFile)             {                 FRN = lFRN;                 ParentFRN = lParentFSN;                 FileName = sFileName;                 IsFile = bIsFile;             }         }         private IntPtr OpenVolume(string szDriveLetter)         {             IntPtr hCJ = default(IntPtr);             //// volume handle             m_DriveLetter = szDriveLetter;             hCJ = CreateFile(@"\\.\" + szDriveLetter, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);             return hCJ;         }         private void Cleanup()         {             if (m_hCJ != IntPtr.Zero)             {                 // Close the volume handle.                 CloseHandle(m_hCJ);                 m_hCJ = INVALID_HANDLE_VALUE;             }             if (m_Buffer != IntPtr.Zero)             {                 // Free the allocated memory                 Marshal.FreeHGlobal(m_Buffer);                 m_Buffer = IntPtr.Zero;             }         }         public IEnumerable<String> EnumerateFiles(string szDriveLetter)         {             try             {                 var usnRecord = default(USN_RECORD);                 var mft = default(MFT_ENUM_DATA);                 var dwRetBytes = 0;                 var cb = 0;                 var dicFRNLookup = new Dictionary<long, FSNode>();                 var bIsFile = false;                 // This shouldn't be called more than once.                 if (m_Buffer.ToInt32() != 0)                 {                     throw new Exception("invalid buffer");                 }                 // Assign buffer size                 m_BufferSize = 65536;                 //64KB                 // Allocate a buffer to use for reading records.                 m_Buffer = Marshal.AllocHGlobal(m_BufferSize);                 // correct path                 szDriveLetter = szDriveLetter.TrimEnd('\\');                 // Open the volume handle                 m_hCJ = OpenVolume(szDriveLetter);                 // Check if the volume handle is valid.                 if (m_hCJ == INVALID_HANDLE_VALUE)                 {                     string errorMsg = "Couldn't open handle to the volume.";                     if (!IsAdministrator())                         errorMsg += "Current user is not administrator";                     throw new Exception(errorMsg);                 }                 mft.StartFileReferenceNumber = 0;                 mft.LowUsn = 0;                 mft.HighUsn = long.MaxValue;                 do                 {                     if (DeviceIoControl(m_hCJ, FSCTL_ENUM_USN_DATA, ref mft, Marshal.SizeOf(mft), m_Buffer, m_BufferSize, ref dwRetBytes, IntPtr.Zero))                     {                         cb = dwRetBytes;                         // Pointer to the first record                         IntPtr pUsnRecord = new IntPtr(m_Buffer.ToInt32() + 8);                         while ((dwRetBytes > 8))                         {                             // Copy pointer to USN_RECORD structure.                             usnRecord = (USN_RECORD)Marshal.PtrToStructure(pUsnRecord, usnRecord.GetType());                             // The filename within the USN_RECORD.                             string FileName = Marshal.PtrToStringUni(new IntPtr(pUsnRecord.ToInt32() + usnRecord.FileNameOffset), usnRecord.FileNameLength / 2);                             bIsFile = !usnRecord.FileAttributes.HasFlag(FileAttributes.Directory);                             dicFRNLookup.Add(usnRecord.FileReferenceNumber, new FSNode(usnRecord.FileReferenceNumber, usnRecord.ParentFileReferenceNumber, FileName, bIsFile));                             // Pointer to the next record in the buffer.                             pUsnRecord = new IntPtr(pUsnRecord.ToInt32() + usnRecord.RecordLength);                             dwRetBytes -= usnRecord.RecordLength;                         }                         // The first 8 bytes is always the start of the next USN.                         mft.StartFileReferenceNumber = Marshal.ReadInt64(m_Buffer, 0);                     }                     else                     {                         break; // TODO: might not be correct. Was : Exit Do                     }                 } while (!(cb <= 8));                 // Resolve all paths for Files                 foreach (FSNode oFSNode in dicFRNLookup.Values.Where(o => o.IsFile))                 {                     string sFullPath = oFSNode.FileName;                     FSNode oParentFSNode = oFSNode;                     while (dicFRNLookup.TryGetValue(oParentFSNode.ParentFRN, out oParentFSNode))                     {                         sFullPath = string.Concat(oParentFSNode.FileName, @"\", sFullPath);                     }                     sFullPath = string.Concat(szDriveLetter, @"\", sFullPath);                     yield return sFullPath;                 }             }             finally             {                 //// cleanup                 Cleanup();             }         }         public static bool IsAdministrator()         {             WindowsIdentity identity = WindowsIdentity.GetCurrent();             WindowsPrincipal principal = new WindowsPrincipal(identity);             return principal.IsInRole(WindowsBuiltInRole.Administrator);         }     }

本文还提供了一个扩展方法,方便我们获取某个磁盘下的所有的文件名。 

    public static class DriveInfoExtension     {         public static IEnumerable<String> EnumerateFiles(this DriveInfo drive)         {             return (new MFTScanner()).EnumerateFiles(drive.Name);         }     }

需要注意的是,读取USN Journal是需要管理员权限的,因此使用这个类需要管理员权限才能正常运行。

另外,这个类封装的也略为简单,只读取了文件名,实际上还可以读取文件大小,属性等常用信息,修改一下代码非常容易获取这些属性。通过它们可以非常方便写出一些分析磁盘空间占用的程序,这里就不举例了。

以上就是关于“如何用C#代码实现快速查询文件”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI