Everything是如何搜索的

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/myinc/article/details/54949190

写在前面

使用了Everything之后,一直对他的搜索速度感兴趣,在网上也看了很多对其原理的揭秘,终于有空找了个源码研究了一下,原理就是对NTFS的USN特性进行使用。

原理

详细解释我参照别人家的博客来一段:

当扇区的文件有变化时,操作系统会往USN Journal文件中追加一条记录,该记录包含文件名、变化发生的时间、变化的原因等信息,而不包含变化的内容。每一条记录用一个64位数字标识,称作USN(UpdateSequence Number)。微软用每一条记录在日志文件中的偏移作为该记录的USN,这样可以快速地通过USN获取到对应的记录。显而易见,USN是递增的,但是不连续。

所以如果想获得磁盘的文件只需要读取日志即可。

网上的源码有很多,关于读取日志,从日志转换成完整路径都不难理解,如果想自己写一个也是可以的。

问题

我认为需要考虑的主要问题:
1. 从上次读取的位置继续读取;
2. 新增或删除文件处理。

Everything 源码超级简述

源码仔细看并不难理解。
UsnOperator 类中,我认为比较重要的一点,是如何继续读取

public List<UsnEntry> GetEntries()
{
    var result = new List<UsnEntry>();
    UsnErrorCode usnErrorCode = this.QueryUSNJournal();
    if (usnErrorCode == UsnErrorCode.SUCCESS)
    {
        MFT_ENUM_DATA mftEnumData = new MFT_ENUM_DATA();
        mftEnumData.StartFileReferenceNumber = 0;

        // 如果想从上次的位置继续读取日志
        // 将lowUsn修改至上次最后一个UsnEntry.Usn即可
        mftEnumData.LowUsn = 0;
        mftEnumData.HighUsn = this.ntfsUsnJournalData.NextUsn;

        int sizeMftEnumData = Marshal.SizeOf(mftEnumData);
        IntPtr ptrMftEnumData = GetHeapGlobalPtr(sizeMftEnumData);
        Marshal.StructureToPtr(mftEnumData, ptrMftEnumData, true);

        int ptrDataSize = sizeof(UInt64) + 10000;
        IntPtr ptrData = GetHeapGlobalPtr(ptrDataSize);

        uint outBytesCount;

        while (false != Win32Api.DeviceIoControl(
            this.DriveRootHandle,
            UsnControlCode.FSCTL_ENUM_USN_DATA,
            ptrMftEnumData,
            sizeMftEnumData,
            ptrData,
            ptrDataSize,
            out outBytesCount,
            IntPtr.Zero))
        {

            IntPtr ptrUsnRecord = new IntPtr(ptrData.ToInt32() + sizeof(Int64));
            while (outBytesCount > 60)
            {
                var usnRecord = new USN_RECORD_V2(ptrUsnRecord);
                result.Add(new UsnEntry(usnRecord));
                ptrUsnRecord = new IntPtr(ptrUsnRecord.ToInt32() + usnRecord.RecordLength);
                outBytesCount -= usnRecord.RecordLength;
            }

            Marshal.WriteInt64(ptrMftEnumData, Marshal.ReadInt64(ptrData, 0));
        }

        Marshal.FreeHGlobal(ptrData);
        Marshal.FreeHGlobal(ptrMftEnumData);
    }
    return result;
}

使用 FileSystemWatcher 监听文件变化

关于电脑文件的修改监听,C#有相应的类来处理,非常方便,感兴趣可深挖:

FileSystemWatcher _watcher = new FileSystemWatcher(@"J:\", "*.*");
_watcher.Created += new FileSystemEventHandler(OnProcess);
_watcher.Changed += new FileSystemEventHandler(OnProcess);
_watcher.Deleted += new FileSystemEventHandler(OnProcess);
_watcher.Renamed += new RenamedEventHandler(OnFileRenamed);
_watcher.IncludeSubdirectories = true;
_watcher.EnableRaisingEvents = true;

下载

Everything相关资料下载

参考资料

DeviceIOControl详解-各个击破

展开阅读全文

没有更多推荐了,返回首页