Everything研究之读取NTFS下的USN日志文件(1)

转自:http://univasity.iteye.com/blog/805234


  http://univasity.iteye.com/blog/805235


我在第一次使用 Everything 时,对其速度确实感到惊讶,后来了解到是通过操作 USN 实现的,并且有一定的局限性(只有 NTFS 下才能使用)。

 

近来清闲无事(失业了),搞些自己的小项目玩玩。其中也要处理到本地搜索这块,首先我想到的就是Everything 。

 

我仔细地将官网和他论坛的帖子都看了遍,基本没找到什么讲到原理的。倒是官网上提供了一个 Everything 的SDK 下载,是一个 IPC 的实现(我不是很懂,大概是程序关联之类的),需要 Everything 在后台跑才能调用操作。我也试了下效果,可以实现的,就是这样太麻烦了。

 

经过多日的搜搜,我发现了一个帖子,讨论的正是对 USN 的操作,同时我搜到了回帖者的 BLOG ,这一切让我有了开始的基础 …

 

 

言归正传:

 

初步认识 USN :

USN Journal 相当于 NTFS 的秘书,为他记录下改动的一切,并储存为 USN_RECORD 的格式。

更多的介绍请看以下链接:

Keeping an Eye on Your NTFS Drives: the Windows 2000 Change Journal Explained

fsutil_usn

NTFS文件系统 USN日志

 

下面来分享下近日研究的成果,一步步来探索 Everything 神奇的速度 USN的使用(Everything的快不单是用了USN,还需要建立索引,原来表达有误,改过来)

整个实现分为 6 步:

1.       判断驱动盘是否为 NTFS 格式

2.       获取驱动盘句柄

3.       初始化 USN 日志文件

4.       获取 USN 基本信息

5.       列出 USN 日志的所有数据

6.       删除 USN 日志文件

 

第一步:判断驱动盘是否 NTFS 格式

我们可以通过 GetVolumeInformation() 函数获取相关的信息进行判断。

可参考 MSDN : http://msdn.microsoft.com/en-us/library/aa364993%28VS.85%29.aspx

 

[[

这里我还找到了一个中文的说明:

GetVolumeInformation(

  lpRootPathName: PChar;               { 磁盘驱动器代码字符串}

  lpVolumeNameBuffer: PChar;           { 磁盘驱动器卷标名称}

  nVolumeNameSize: DWORD;              { 磁盘驱动器卷标名称长度}

  lpVolumeSerialNumber: PDWORD;        { 磁盘驱动器卷标序列号}

  var lpMaximumComponentLength: DWORD; { 系统允许的最大文件名长度}

  var lpFileSystemFlags: DWORD;        { 文件系统标识}

  lpFileSystemNameBuffer: PChar;       { 文件操作系统名称}

  nFileSystemNameSize: DWORD           { 文件操作系统名称长度}

): BOOL;

上图可以看到,最后一个就是格式类型了,对应 lpFileSystemNameBuffer 。

]]

 

下面给出C++ 的实现作为参考:

Cpp代码   收藏代码
  1. /** 
  2.  * step 01. 判断驱动盘是否 NTFS 格式 
  3.  */  
  4. char sysNameBuf[MAX_PATH] = {0};  
  5. int status = GetVolumeInformationA(volName,  
  6.                                    NULL, // 驱动盘名缓冲,这里我们不需要  
  7.                                    0,  
  8.                                    NULL,  
  9.                                    NULL,  
  10.                                    NULL,  
  11.                                    sysNameBuf, // 驱动盘的系统名( FAT/NTFS)  
  12.                                    MAX_PATH);  
  13.   
  14. if (0!=status){  
  15.   
  16.     printf(" 文件系统名 : %s\n" , sysNameBuf);  
  17.   
  18.     // 比较字符串  
  19.     if (0==strcmp(sysNameBuf, "NTFS" )){  
  20.         isNTFS = true ;  
  21.     }else {  
  22.         printf(" 该驱动盘非 NTFS 格式 \n" );  
  23.     }  
  24.   
  25. }   
 

 

USN Journal 并非一开始就存在的,需要手动打开。我们可以使用函数 DeviceIoControl() 并通过参数FSCTL_CREATE_USN_JOURNAL 来操作。但仔细看 MSDN 会发现,需要先通过 CreateFile() 获取一个驱动盘的句柄。很多的后续操作都要用到这个句柄。

 

第二步:获取驱动盘句柄

可参考 MSDN : http://msdn.microsoft.com/en-us/library/aa363858%28VS.85%29.aspx

 

[[

对于我们目前的操作,注意看最后 Remarks ,

Physical Disks and Volumes ” 中的一段:

The following requirements must be met for such a call to succeed:

  • The caller must have administrative privileges. For more information, see Running with Special Privileges .
  • The dwCreationDisposition parameter must have the OPEN_EXISTINGflag.
  • When opening a volume or floppy disk, the dwShareMode parameter must have the FILE_SHARE_WRITEflag.

大概意思是,要成功执行需要满足一下条件:

1.  使用者需要获取管理员权限

2.  dwCreationDisposition 参数 ( 倒数第三个 ) 必须带有 OPEN_EXISTIN 标识

3.  当打开一个驱动盘或软盘 , dwShareMode 参数 ( 第三个 ) 必须带有 FILE_SHARE_WRITE 标识

 

再有就是 ”Files ” 中的一段 :

Windows Server 2003 and Windows XP/2000: 

If CREATE_ALWAYS and FILE_ATTRIBUTE_NORMAL are specified, CreateFile fails and sets the last error to ERROR_ACCESS_DENIED if the file exists and has the FILE_ATTRIBUTE_HIDDEN or FILE_ATTRIBUTE_SYSTEM attribute. To avoid the error, specify the same attributes as the existing file.

 

大概意思是:

在 windows2003,xp 和 2000 中如果设定了 CREATE_ALWAYS 和 FILE_ATTRIBUTE_NORMAL 两个属性,如果文件存在,并带有属性 FILE_ATTRIBUTE_HIDDEN 或 FILE_ATTRIBUTE_SYSTEM 的话, CreateFile 会失败,并且返回的错误信息为 ERROR_ACCESS_DENIED 。要避免这个错误,需要制定与文件本身相同的属性。

 

>> 所以我们这里尽量不使用 CREATE_ALWAYS 和 FILE_ATTRIBUTE_NORMAL 。我这里使用FILE_ATTRIBUTE_HIDDEN 。

]]

 

 

照样贴上例子(我很少用 C++ ,写得不好,仅参考) :

Cpp代码   收藏代码
  1. /** 
  2.  * step 02. 获取驱动盘句柄 
  3.  */  
  4. char fileName[MAX_PATH];  
  5. fileName[0] = '\0';  
  6.   
  7. // 传入的文件名必须为\\.\C:的形式  
  8. strcpy(fileName, "\\\\.\\");  
  9. strcat(fileName, volName);  
  10. // 为了方便操作,这里转为string进行去尾  
  11. string fileNameStr = (string)fileName;  
  12. fileNameStr.erase(fileNameStr.find_last_of(":")+1);  
  13.   
  14. printf("驱动盘地址: %s\n", fileNameStr.data());  
  15.   
  16. // 调用该函数需要管理员权限  
  17. hVol = CreateFileA(fileNameStr.data(),  
  18.                    GENERIC_READ | GENERIC_WRITE, // 可以为0  
  19.                    FILE_SHARE_READ | FILE_SHARE_WRITE, // 必须包含有FILE_SHARE_WRITE  
  20.                    NULL, // 这里不需要  
  21.                    OPEN_EXISTING, // 必须包含OPEN_EXISTING, CREATE_ALWAYS可能会导致错误  
  22.                    FILE_ATTRIBUTE_READONLY, // FILE_ATTRIBUTE_NORMAL可能会导致错误  
  23.                    NULL); // 这里不需要  
  24.   
  25. if(INVALID_HANDLE_VALUE!=hVol){  
  26.     getHandleSuccess = true;  
  27. }else{  
  28.     printf("获取驱动盘句柄失败 —— handle:%x error:%d\n", hVol, GetLastError());  
  29. }  
 

 

第三步:打开 USN Journal 文件

MSDN : http://msdn.microsoft.com/en-us/library/aa364558%28v=VS.85%29.aspx

 

 

代码参考:

Cpp代码   收藏代码
  1. /** 
  2.  * step 03. 初始化USN日志文件 
  3.  */  
  4. DWORD br;  
  5. CREATE_USN_JOURNAL_DATA cujd;  
  6. cujd.MaximumSize = 0; // 0表示使用默认值  
  7. cujd.AllocationDelta = 0; // 0表示使用默认值  
  8. status = DeviceIoControl(hVol,  
  9.                          FSCTL_CREATE_USN_JOURNAL,  
  10.                          &cujd,  
  11.                          sizeof(cujd),  
  12.                          NULL,  
  13.                          0,  
  14.                          &br,  
  15.                          NULL);  
  16.   
  17. if(0!=status){  
  18.     initUsnJournalSuccess = true;  
  19. }else{  
  20.     printf("初始化USN日志文件失败 —— status:%x error:%d\n", status, GetLastError());  
  21. }  
 

 

这时如果你能成功创建 USN 日志,那么对 USN 的探索即将开始 …

 

>> 目前你手上有的资源是 :

1.  某个 NTFS 驱动盘的 HANDLE;

2.  该驱动盘的 USN 日记已成功创建 .

 

/******************************************

 2010.11.10更新了代码,调整了一处地方,lowUsn的设置。

 

******************************************/

 

第四步:获取 USN Journal 文件的基本信息

MSDN: http://msdn.microsoft.com/en-us/library/aa364583%28v=VS.85%29.aspx

 

[[

他是这么一个结构:

typedef struct {

  DWORDLONG UsnJournalID;

  USN       FirstUsn;

  USN       NextUsn;

  USN       LowestValidUsn;

  USN       MaxUsn;

  DWORDLONG MaximumSize;

  DWORDLONG AllocationDelta;

} USN_JOURNAL_DATA, *PUSN_JOURNAL_DATA;

 

其中的 UsnJournalID ,FirstUsn ,NextUsn 是我们后续操作需要用到的。

 

获取他很简单,通过DeviceIoControl() 配合 FSCTL_QUERY_USN_JOURNAL 来实现。

]]

 

 

给出一个实现参考 :

Cpp代码   收藏代码
  1. bool getBasicInfoSuccess = false;  
  2.   
  3. /** 
  4.  * step 04. 获取USN日志基本信息(用于后续操作) 
  5.  * msdn:http://msdn.microsoft.com/en-us/library/aa364583%28v=VS.85%29.aspx 
  6.  */  
  7. DWORD br;  
  8. status = DeviceIoControl(hVol,  
  9.                          FSCTL_QUERY_USN_JOURNAL,  
  10.                          NULL,  
  11.                          0,  
  12.              &UsnInfo,  
  13.              sizeof(UsnInfo),  
  14.              &br,  
  15.              NULL);  
  16.   
  17. if(0!=status){  
  18.     getBasicInfoSuccess = true;  
  19. }else{  
  20.     printf("获取USN日志基本信息失败 —— status:%x error:%d\n", status, GetLastError());  
  21. }  

 

第五步:列出 USN Journal 文件的数据

前面提到 USN 日志的数据是以 USN_RECORD 形式储存的,在 MSDN 的介绍:

http://msdn.microsoft.com/en-us/library/aa365722%28VS.85%29.aspx

[[

同时分享一个网上找到的带中文注释的 USN_RECORD : ( 原文链接 )

typedef struct {

DWORD RecordLength; // 记录长度

WORD MajorVersion; // 主版本

WORD MinorVersion; // 次版本

DWORDLONG FileReferenceNumber; // 文件引用数

DWORDLONG ParentFileReferenceNumber; // 父目录引用数

USN Usn; // USN

LARGE_INTEGER TimeStamp; // 时间戳

DWORD Reason; // 原因

DWORD SourceInfo; // 源信息

DWORD SecurityId; // 安全

ID DWORD FileAttributes; // 文件属性

WORD FileNameLength; // 文件长度

WORD FileNameOffset; // penultimate of original version 2.0 < 文件名偏移 >

DWORD ExtraInfo1; // Hypothetically added in version 2.1

DWORD ExtraInfo2; // Hypothetically added in version 2.2

DWORD ExtraInfo3; // Hypothetically added in version 2.3

WCHAR FileName[1]; // variable length always at the end < 文件名第一位的指针 >

} USN_RECORD, *PUSN_RECORD;

 

其中 <> 是我补充上的,要实现类似 Everything 的搜索,我们主要关注下面几个参数:

FileReferenceNumber, ParentFileReferenceNumber -> 可以用来找回文件路径

FileNameLength, FileName[1] -> 储存了文件名

]]

 

需要枚举 USN 的数据,我们需要使用 DeviceIoControl() 和 FSCTL_ENUM_USN_DATA 配合。

MSDN : http://msdn.microsoft.com/en-us/library/aa364563%28v=VS.85%29.aspx

 

这里需要提供一个 MTF_ENUM_DATA 的结构作为参数 , 正如描述所指:

Enumerates the update sequence number (USN) data between two specified boundaries to obtain master file table (MFT) records.

 

这些 USN_RECORD 储存在一个叫 MFT 的表里, MTF_ENUM_DATA 的作用就是制定一个范围 。对这个我也不是很了解,不管他,把参数填上看看结果再说。

 

[[

关键就是如何构建一个 MFT_ENUM_DATA 的结构来指定获取数据的范围,我们来看一下这个结构:

typedef struct {

  DWORDLONG StartFileReferenceNumber;

  USN       LowUsn;

  USN       HighUsn;

} MFT_ENUM_DATA, *PMFT_ENUM_DATA;

 

最后我在 MSDN 中找到关键的一段话:

The first call to FSCTL_ENUM_USN_DATA during an enumeration must have the StartFileReferenceNumber member set to (DWORDLONG)0. Each call to FSCTL_ENUM_USN_DATA retrieves the starting point for the subsequent call as the first entry in the output buffer. Subsequent calls must be made with StartFileReferenceNumber set to this value. For more information, seeFSCTL_ENUM_USN_DATA .

大概意思是:

初始时将 StartFileReferenceNumber 设置为 0 ,然后每次进行枚举后获取起始点进行下一次操作,这个新的起始点包含在返回的 buffer 的开头。

 

我们不难发现,这里指的 buffer 就是 DeviceIoControl 函数中的:

BOOL DeviceIoControl(

  (HANDLE) hDevice,            // handle to volume

  FSCTL_ENUM_USN_DATA,         // dwIoControlCode

  (LPVOID) lpInBuffer,         // input buffer

  (DWORD) nInBufferSize,       // size of input buffer

  (LPVOID) lpOutBuffer,        // output buffer < 这里>

  (DWORD) nOutBufferSize,      // size of output buffer

  (LPDWORD) lpBytesReturned,   // number of bytes returned

  (LPOVERLAPPED) lpOverlapped  // OVERLAPPED structure

);

 

在 MFT_ENUM_DATA 中 还有另外两个参数:

LowUsn, HighUsn

分别制定范围的起止。

 

我们这里要获取所有USN 的数据,需要知道整个USN 的起止位置。可通过 DeviceIoControl() 配合FSCTL_QUERY_USN_JOURNAL 来获取一个 USN_JOURNAL_DATA 结构体,里面包含我们需要的信息 ( 后续的删除操作也要用到这些信息 ) :

typedef struct {

  DWORDLONG UsnJournalID;

  USN       FirstUsn;

  USN       NextUsn;

  USN       LowestValidUsn;

  USN       MaxUsn;

  DWORDLONG MaximumSize;

  DWORDLONG AllocationDelta;

} USN_JOURNAL_DATA, *PUSN_JOURNAL_DATA;

 

其中的FirstUsn 和NextUsn 就分别对应了LowUsn 和HighUsn.

]]

 

首先需要构建一个MFT_ENUM_DATA ,我们用上一步获取到的USN_JOURNAL_DATA 进行填充。  

这里给出一个实现参考:

 

Cpp代码   收藏代码
  1. MFT_ENUM_DATA med;  
  2. med.StartFileReferenceNumber = 0;  
  3. med.LowUsn = 0;//UsnInfo.FirstUsn; 这里经测试发现,如果用FirstUsn有时候不正确,导致获取到不完整的数据,还是直接写0好.  
  4. med.HighUsn = UsnInfo.NextUsn;   
 

 

有了MFT_ENUM_DATA ,就可以获取到USN 的数据了。

MSDN上也提供了一个例子可做参考 ,虽然是FSCTL_READ_USN_JOURNAL,和我们要执行的ENUM是类似的。

 

枚举USN数据,这里给出实现参考:

Cpp代码   收藏代码
  1. #define BUF_LEN 4096  
  2.   
  3. CHAR buffer[BUF_LEN]; // 用于储存记录的缓冲 , 尽量足够地大  
  4.   
  5. DWORD usnDataSize;  
  6.   
  7. PUSN_RECORD UsnRecord;  
  8.   
  9. while (0!=DeviceIoControl(hVol,  
  10.                           FSCTL_ENUM_USN_DATA,  
  11.                           &med,  
  12.                           sizeof (med),  
  13.                           buffer,  
  14.                           BUF_LEN,  
  15.                           &usnDataSize,  
  16.                           NULL))  
  17. {  
  18.   
  19.     DWORD dwRetBytes = usnDataSize - sizeof (USN);  
  20.   
  21.     // 找到第一个 USN 记录  
  22.     // from MSDN(http://msdn.microsoft.com/en-us/library/aa365736%28v=VS.85%29.aspx ):  
  23.     // return a USN followed by zero or more change journal records, each in a USN_RECORD structure.  
  24.     UsnRecord = (PUSN_RECORD)(((PCHAR)buffer)+sizeof (USN));  
  25.   
  26.     printf(" ********************************** \n" );  
  27.   
  28.     while (dwRetBytes>0){  
  29.   
  30.         // 打印获取到的信息  
  31.         const int strLen = UsnRecord->FileNameLength;  
  32.         char fileName[MAX_PATH] = {0};  
  33.         WideCharToMultiByte(CP_OEMCP,NULL,UsnRecord->FileName,strLen/2,fileName,strLen,NULL,FALSE);  
  34.   
  35.        printf("FileName: %s\n" , fileName);  
  36.        // 下面两个 file reference number 可以用来获取文件的路径信息  
  37.        printf("FileReferenceNumber: %xI64\n" , UsnRecord->FileReferenceNumber);  
  38.        printf("ParentFileReferenceNumber: %xI64\n" , UsnRecord->ParentFileReferenceNumber);  
  39.        printf("\n" );  
  40.   
  41.        // 获取下一个记录  
  42.        DWORD recordLen = UsnRecord->RecordLength;  
  43.        dwRetBytes -= recordLen;  
  44.        UsnRecord = (PUSN_RECORD)(((PCHAR)UsnRecord)+recordLen);  
  45.       
  46.     }  
  47.   
  48.     // 获取下一页数据, MTF 大概是分多页来储存的吧?  
  49.     // from MSDN(http://msdn.microsoft.com/en-us/library/aa365736%28v=VS.85%29.aspx ):  
  50.     // The USN returned as the first item in the output buffer is the USN of the next record number to be retrieved.  
  51.     // Use this value to continue reading records from the end boundary forward.  
  52.     med.StartFileReferenceNumber = *(USN *)&buffer;  
  53.   
  54. }   
 

 

现在只要对列出的数据进行筛选,基本就可以实现 Everything 的快速搜索了。

还需要结合索引的建立,才能达到更快的速度。

 

下面再介绍下如何删除 USN Journal 文件,当你不再需要他的时候。

 

第六步:删除 USN Journal 文件

MSDN 参考: http://msdn.microsoft.com/en-us/library/aa363928%28v=VS.85%29.aspx

 

实现参考:

Cpp代码   收藏代码
  1. /** 
  2.  * step 06. 删除 USN 日志文件 ( 当然也可以不删除 ) 
  3.  */  
  4. DELETE_USN_JOURNAL_DATA dujd;  
  5. dujd.UsnJournalID = UsnInfo.UsnJournalID;  
  6. dujd.DeleteFlags = USN_DELETE_FLAG_DELETE;  
  7.   
  8. int status = DeviceIoControl(hVol,  
  9.                              FSCTL_DELETE_USN_JOURNAL,  
  10.                              &dujd,  
  11.                              sizeof (dujd),  
  12.                              NULL,  
  13.                              0,  
  14.                              &br,  
  15.                              NULL);  
  16.   
  17. if (0!=status){  
  18.     printf(" 成功删除 USN 日志文件 !\n" );  
  19. }else {  
  20.     printf(" 删除 USN 日志文件失败 —— status:%x error:%d\n" , status, GetLastError());  
  21. }   
 

 

拓展实现:通过 File Reference Number 获取文件路径

这个这里暂时不讲了,感兴趣的可以参考文章最后给出的链接的实现。

C++上可以通过使用NtCreateFile()和NtQueryFileInformation()来实现路径获取。
基本MSDN上有比较详细的说明了。

===================================================================================================================
>>最后
附上一个完整的C++实现的例子:
   
NftsUsnJournalDemo_2010.11.10_.rar 

另外,还有一个在国外BLOG找到的C#实现的例子,比较完成,注释也很清晰。我也参考了不少。
原BLOG上是以文本贴出代码的,我这里整理成可编译的项目提供下载。
原文BLOG:http://www.dreamincode.net/forums/blog/1017-stcroixskippers-blog/ 
整理的项目:
 UsnJournalProject_v1.3.rar


===================================================================================================================
以上都是出于个人兴趣的研究,接触C++实在迫不得已……Java某些部分的局限性太大了。


上面很多东西都是GOOGLE+MSDN完成的,若有疏忽请指教。


下一步准备将这些基本操作封装成DLL,再通过JNI供JAVA使用。欢迎交流。

 



  • 10
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Everything:速度最快的文件搜索工具 转载善用佳软,本人用的时候都是用alt+F快捷键的,这个需要到选项设置一下,检索速度太快,占用内存平时7MB左右,不能检索文件内容,仅文件名。可以开启http或ftp服务,用来共享文件还是不错的,毕竟校网传输速度不错,方便 Everything是速度最快的文件搜索软件。其速度之快令人震惊,百G硬盘几十万个文件,可以在几秒钟之内完成索引;文件名搜索瞬间呈现结果。它小巧免费,支持中文,支持正则表达式,可以通过HTTP或FTP分享搜索结果。如果不满意Windows自带的搜索工具、Total Commander的搜索、Google 桌面搜索或百度硬盘搜索,如果正在使用或放弃了Locate32,都值得推荐这款体积小巧、免安装、免费、速度极快(比Locate32更快)的文件搜索工具Everything! 最新beta版。 中文语言包、语言包txt文本 本文目录:简介、初级教程、视频演示、技巧、补充、总结、附录 1. Everything简介 voidtools(中文主页)开发的一款文件搜索工具,官网描述为“基于名称实时定位文件和目录(Locate files and folders by name instantly)”。它体积小巧,界面简洁易用,快速建立索引,快速搜索,同时占用极低的系统资源,实时跟踪文件变化,并且还可以通过http或ftp形式分享搜索。 注意: - 只搜索文件名,不能搜索文件内容; - 只适用NTFS文件系统,不适合FAT32; - 完美支持中文,但必须使用V1.2.及更新版本。 2. 初级教程:Everything的基本用法 2.1 下载与安装 官方下载页。 安装或解压Everything,即可开始使用。 2.2 首次运行 Everything在第一次运行时,会建立索引数据库。但你丝毫不用担心,其速度极快,生成的索引文件极小!看看本文下面的回复,你会充满信心。亲身体验之后,你或者也会为其速度震惊。或者,你根本没感觉到它需要建立索引。 索引之后,简洁的程序界面呈现在你的面前,程序状态栏中还会显示索引的文件数量。看到这个数字,你是否惊奇Everything的神速呢? 2.3 基本搜索 尽管Everything还处在英文界面,但这并不影响你的基本使用。只须在搜索框中,输入几个字母或汉字,搜索结果就会实时呈现在你的眼前。然后,可以直接双击某条结果,打开文件。也可以直接在结果中进行复制、删除等常见操作。 2.4 切换为中文界面 中文语言包,并将语言包内的Everything.lng解压到程序目录,就可以通过菜单切换为中文了:Tools→ Options→ General→ Language→ 简体中文。 需要说明的是,切换语言后,需要重启Everything才能看到效果。另外,点击Everything窗口的关闭按钮后,它只是缩小为托盘图标,并没有真正关闭。 3. Everything搜索技巧 3.1 高效搜索之“与”“或” 技巧:在Everything的搜索框中可以输入多个关键词,以空格分开,表示搜索结果要包括全部关键词。大家肯定对这种做法不会陌生,因为它正是搜索引擎的惯例。 举例:键入(不包括引号,下同)“李白 北京 08 jpg”,可以快速找出某些照片。 技巧:对应“与”的还有“或”(OR)运算,用半角竖线表示:|。当你不确信关键词的准确描述时,这种方式非常有用。 举例:“jpg 李白|libai 北京 08”、“免费|freeware”…… 引伸:既然空格表示“与”,那么如何表示真正的空格呢?很简单,加英文半角引号,比如”program files”。 3.2 正则表达式 Everything支持正则表达式,或者说,支持一些简单的正则表达式。但对大多数用户而言,这已经足够了!Everything支持的正则表达式有: | () ? * + . [] [^] ^ $ {m,n} rex网友的翻译。如果你不了解什么是正则表达式,请自行搜索。 3.3 指定搜索范围 默认情况下,Everything索引、搜索所有本地NTFS磁盘的所有目录。但是你可以通过如下方式,限定搜索范围,以得到更易用的结果列表。 - 希望Everything永不索引某个磁盘,请在“选项”-“NTFS磁盘”中,选定相应盘符,取消“搜索本卷”或“包含在数据库中”。(注:可以取消前一项,这样后一项就自动变灰——但没发现这种做法与只取消后一项的差别。大家可以研究一下!) - 希望永远排除某些目录,可以在“选项”-“排除列表”中设定。和上条方法一样,确认之后Everything会重新生成索引。 - 希望Everything只搜索某个目录,可以在资源管理器或Total Commander中,右击该目录,在弹出菜单上选“Search Everything…”。这时你会看到Everything的搜索框中,出现了带引号的目录名。 - 与上一方法相同,只是不用右击目录,而是直接输入带引号的目录名,再输入搜索关键词。需要注意的是:目录名一定是完整路径,且用半角双引号括起来,不能选中“使用正则表达式”。 - 还有一种方法,使用起来要头脑更清楚才行。比如,设定“匹配路径”后,输入 files/ .exe,看看搜到了什么结果,想想这是为什么。 3.4 网络分享 Everything内置了HTTP、ETP/FTP服务器。这意味着,你可以用它当作简单的服务器来用。何况,它的HTTP分享,仍然提供了强大的搜索功能。 HTTP分享:点击菜单“工具”-“HTTP服务器”后,就可以在浏览器访问 http://localhost 或输入本机IP进行访问了。在HTTP中,它的搜索功能一样强大。因此,你可以把它加入Firefox等浏览器的自定义搜索中,更加方便的进行搜索。 FTP功能类似,但不具备搜索功能。 相比而言,因为浏览器更为常用,并且支持搜索,默认的UTF-8编码识别率更高,所以推荐HTTP方式分享。无论是HTTP还是FTP,其端口、用户名、密码都是可以设定的。这样,你就可以在局域网内更放心的分享文件了。 除了与朋友分享之外,在文件服务器上运行Everything,然后用户就可以通过浏览器快速搜索了。这是一个很好的应用。 4. 一些补充 4.1 everything的速度 Everything搜索工具的最大优点是速度。其速度不是快,是极快;用户不是满意,而是震惊。 第一个快速体现在索引速度。官网称,1分钟可索引100万个文件。笔者的NTFS文件系统共40G/近4万个文件,第一次启动时,根本没有感觉到建立索引需要时间。这种快速,是因为Everything的索引无需逐一扫描硬盘文件,而是直接读取NTFS文件系统的USN日志。这当然是既省力,又合理的做法。 第二个快速体现在搜索速度。在搜索框中键入字符后,搜索结果——或许称为过滤结果更准确——实时呈现。 Locate32。是否真有这么快?请各位读者反馈试用结果。目前收到的反馈都证明了这一点,对有些网友而言,速度已经快到令人震惊,甚至是愤怒了:凭什么可以这么快! 4.2 Everything资源占用 总起来讲,占用资源很少。 - 从安装(实际解压即可)来看,真正需要的只有一个主文件exe,约0.5MB。 - 索引数据库极小。笔者60G硬盘,索引文件0.7MB。 - 占用内存少,笔者使用为7MB。 4.3 Everything数据库更新 - 没有所谓更新频率的设定,因为更新是自动的。 - 每次重启Everything,都会自动更新; - 每次设置Everything(比如设定排除列表)之后,都会自动更新; - Everything运行时,会实时更新索引数据库。 4.4 Everything可与其他文件管理器(如Total Commander)集成 以下内容由网友dracodoc于2008-11-18 1:17补充。Everything集成Total Commander Everything FAQ有介绍。 我的修改: explore_folder_command=$exec(”%SystemRoot%\explorer.exe” /n,/e,”%1″) explore_folder_path_command=$exec(”%SystemRoot%\explorer.exe” /n,/e,/select,”%1″) open_folder_path_command=$exec(”d:\app\wincmd\TOTALCMD.EXE” “$parent(%1)”) open_file_command=$exec(”%1″) open_folder_command=$exec(”d:\app\wincmd\TOTALCMD.EXE” “%1″) explore部分不用变,保留第二种选择。需要在tc里设定只打开一个tc实例,我试过用tc命令行的/o参数来不打开第二个实例,但是everything不认。 现在双击找到的文件会打开,双击目录会激活tc跳到该目录(如果你想设定在左边,右边或者新建一个tab可以尝试加上tc的命令行参数,不一定能用),右键选择文件,open path会用tc打开文件所在目录。 再在tc里或者其他全局hotkey设定程序里设定everything的激活热键就可以了(我不喜欢一直开着,随用随启动并不慢) 下载最新beta版。低版本Everything无法识别上述ini内容,会强行删除。“在tc里设定只打开一个tc实例”的做法有2种。一是图形化操作(推荐):配置 → 操作方式 → 主程序 → 只允许一个TC运行。二是直接在wincmd.ini中的[Configuration]段增加一句 onlyonce=1,并重启TC。 5. 结论 如果你经常需要按照文件名进行快速搜索,并且磁盘用了NTFS文件系统,则Everything是首荐工具。如果你需要远程搜索其他计算机上的文件,那么Everything的服务器共享功能更为适合。总之,这款不到1MB的搜索利器,很值得收藏试用。 附录 用Everything在電光石火間找到迷失的檔案。于是,我也在翻译完成之前先发此文,以便合力宣传everything。 友好竞争的关系,都是小巧、免费的佳作。bbinn还有一款文件查重小软件FindDump,也在上面的贴子中。 网友评论:(评论内容只代表网友观点,与本站立场无关!) 【发表评论】 评论人 评论内容 评论时间 打分 【bavon】 绝对的好东西。 只要大概知道你的文件名包含哪几个字,就可以把文件找出来,而且速度极快 2009-9-1 11:02:29 5分 【comme】 不清楚,我只是自己用着好就发上来了 2008-11-27 17:53:12 3分 【xjdonkey】 用ava find很久了,感觉不错。 这类工具就是搜索文件名的,跟desktop那种全文索引工具没有可比性。 ava find要在线监视文件读写,感觉对硬盘速度有影响,但它建立的索引库大概也就是50M/50G,检索速度非常快了。现在这类工具挺多,确实很有意义,估计微软用不了多久应该就会集成进windows了。 有没有用过的说说它和ava find比有什么优点? 2008-11-27 12:33:01
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值