广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C#实现快速查询文件的方法
  • 725
分享到

C#实现快速查询文件的方法

2024-04-02 19:04:59 725人浏览 八月长安
摘要

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

相信使用过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#实现快速查询文件的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: C#实现快速查询文件的方法

本文链接: https://www.lsjlt.com/news/152027.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C#实现快速查询文件的方法
    相信使用过Everything的人都对其超快的搜索速度印象非常深刻,它的主要原理是通过扫描NTFS磁盘的USN Journal读取的文件列表,而不是磁盘目录,由于USN Journa...
    99+
    2022-11-13
  • C#如何实现快速查询文件
    今天小编给大家分享一下C#如何实现快速查询文件的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。相信使用过Everything的...
    99+
    2023-07-02
  • mysql快速查询的方法
    小编给大家分享一下mysql快速查询的方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!mysql快速查询的方法:1、查询正在运...
    99+
    2022-10-18
  • Linux系统快速查找文件的方法
    本篇内容介绍了“Linux系统快速查找文件的方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Linux常用命令中,有些命令可以帮助我们查找...
    99+
    2023-06-05
  • MYSQL JDBC快速查询响应的方法以及如何快速返回机制的实现
    MYSQL JDBC快速查询响应的方法以及如何快速返回机制的实现,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。 一直很纠结,...
    99+
    2022-10-18
  • 利用LinuxFind命令快速查找文件方法
    目录一、find 命令基本使用方法二、find 命令进阶用法在茫茫的linux系统种我们如何快速的查找文件呢?对于系统文件基本上是有固定的位置的,但是有些软件安装文件是有自定义位置的...
    99+
    2022-12-08
    Linux Find命令查找文件位置 Linux Find命令查找文件 Linux Find命令用法 Find命令使用
  • 利用Linux Find命令快速查找文件方法
    目录一、find 命令基本使用方法二、find 命令进阶用法在茫茫的linux系统种我们如何快速的查找文件呢?对于系统文件基本上是有固定的位置的,但是有些软件安装文件是有自定义位置的,不熟悉的运维人员交接后我们需要重新适...
    99+
    2022-12-08
    LinuxFind命令查找文件位置 LinuxFind命令查找文件 LinuxFind命令用法 Find命令使用
  • C/C++实现快速排序算法的两种方式实例
    目录介绍流程如下实现方式一方式二总结介绍 快速排序是对冒泡排序算法的一种改进,快速排序算法通过多次比较和交换来实现排序。 流程如下 (图片来自百度) 实现 以下有两种实现方式,说是...
    99+
    2022-11-12
  • Mybatis利用分页插件PageHelper快速实现分页查询
    目录前言 首先创建一个Maven项目 数据库中创建一张表设置Mybatis配置文件 编写pojo实体类和mapper接口和mapper映射文件创建测试类总结前言 Mybatis算是...
    99+
    2022-11-12
  • mysql instr条件查询的实现方法
    这篇文章主要介绍“mysql instr条件查询的实现方法”,在日常操作中,相信很多人在mysql instr条件查询的实现方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”mysql instr条件查询的实...
    99+
    2023-06-20
  • C/C++实现快速排序(两种方式)图文详解
    目录介绍实现方式一方式二总结介绍 快速排序是对冒泡排序算法的一种改进,快速排序算法通过多次比较和交换来实现排序。 流程如下:   实现 以下有两种实现方式,说是两种,其...
    99+
    2022-11-12
  • 快速打开Win8共享文件的方法
    总有一些朋友在处理一些工作琐事上而焦头烂额的忙碌,单单在电脑上找寻文件夹便要花费很多的时间,尤其是在处理一些文件的时间,由于需要用到他人电脑里的一些共享文件和图片,之前比较传统的作法便是进入网上邻居去找同事...
    99+
    2022-06-04
    快速 文件 方法
  • mybatis collection 多条件查询的实现方法
    mybatis collection 多条件查询的实现方法 前言: 业务需要通过mybatis 查询返回嵌套集合,嫌多次查询太麻烦,用自带的高级查询解决问题,下边是代码,已测试通过。 说下自己的理解,就是一...
    99+
    2022-10-18
  • C++归并法+快速排序实现链表排序的方法
    本文主要介绍了C++归并法+快速排序实现链表排序的方法,分享给大家,具体如下: 我们可以试用归并排序解决: 对链表归并排序的过程如下。 找到链表的中点,以中点为分界,将链表拆分成...
    99+
    2022-11-12
  • 超详细解析C++实现快速排序算法的方法
    目录一、前言1.分治算法2.分治算法解题方法二、快速排序1.问题分析2.算法设计3.算法分析三、AC代码一、前言 1.分治算法 快速排序,其实是一种分治算法,那么在了解快速排序之前,...
    99+
    2022-11-13
  • 快速查找电脑中的正在共享的文件 关闭文件共享的方法
    要方便更要安全,文件共享过后要养成及时关闭共享的习惯,还要经常检查自己是否还有不必要的共享文件没有关闭,那么怎么来查找哪些文件正在共享?怎样关闭这些共享的文件呢?请看下文详解!支持WIFI无线上网的移动设备越来越多,除了...
    99+
    2023-05-26
    正在共享的文件 关闭文件共享 方法 电脑 文件 关闭 文件共享
  • MySQL嵌套查询实现子查询的方法
    目录一个查询语句嵌套在另一个查询语句内部的查询1.带ANY(SOME)关键字的子查询2.带ALL关键字的子查询3.带EXISTS关键字的子查询4.带IN关键字的子查询5.带比较运算符...
    99+
    2022-11-13
  • C#实现FTP上传文件的方法
    1.通过用FTP进行上传文件,首先要实现建立FTP连接,一般建立FTP连接,需要知道FTP配置有关的信息。一般要在Bean中建立一个ServiceFileInfo.cs文件进行记录,...
    99+
    2022-11-13
  • Navicat快速导入和导出sql文件的方法
    Navicat是一套快速、可靠并价格相当便宜的数据库管理工具,专为简化数据库的管理及降低系统管理成本而设。它的设计符合数据库管理员、开发人员及中小企业的需要。Navicat 是以直觉...
    99+
    2022-11-12
  • C++详解Primer文本查询程序的实现
    15.9的文本查询程序是对12.3节的文本查询程序的扩展,而使用的主要知识也是15章的核心:继承和多态,即面向对象程序设计。 恩,这一节看的过程中,会有很多不理解。特别是在没有把整个...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作