文件系统和文件输入输出
(file system & file I/O)
系统和卷操作
GetLogicalDrives函数:
DWORD GetLogicalDrives(void);
该函数返回一个32位的值,其中每一位代表是否某一个逻辑驱动器存在。(第1位代表A,
第25位代表Z)
GetLogicalDriveStrings函数:
DWORD GetLogicalDriveStrings(DWORD cchBuffer, //
系统中每一个逻辑驱动器相关的
根目录信息将填充该指针指向的缓冲区
LPTSTR lpszBuffer); // 告诉函数缓冲区的最大尺寸
该函数返回保存所有数据所需的字节数.
调用方法:
DWORD dw=GetLogicalDriveStrings(0,NULL);
LPSTR lpDriveStrings=HeapAlloc(GetProcessHeap(),0,dw*sizeof(TCHAR));
GetLogicalDriveStrings(dw,lpDriveStrings);
返回缓冲区的内容和环境串缓冲区有相同的格式:项目之间由0字符分割,在最后有一个另
外的结束符0。
Windows 95:
该函数没有实现。
GetDriveType函数:
UINT GetDriveType(LPTSTR lpszRootPathName);
该函数返回由lpszRootPathName标识的驱动器的类型,见下表:
标识符 含义
0 无法确定驱动器的类型
1 不存在的根目录
DRIVE_REMOVEABLE 磁盘可以从驱动器中移走(软盘驱动器)
DRIVE_FIXED 磁盘不能从驱动器中移走(硬盘驱动器)
DRIVE_REMOTE 驱动器是远程驱动器(网络驱动器)
DRIVE_CDROM 驱动器是一个CD_ROM驱动器
DRIVE_RAMDISK 驱动器是一个RAM盘
获得卷的特定信息
GetVolumeInformation函数:
GetVolumeInformation(LPTSTR lpRootPathName, // 逻辑驱动器的相关根目录
LPTSTR lpVolumeNameBuffer, // 返回卷的名字
DWORD nVolumeNameSize, // 卷缓冲区的尺寸
LPDWORD lpVolumeSerialNumber, // 卷的序列号
LPDWORD lpMaximumComponentLength, //
返回支持的目录名和文件名的最大字符数
LPDWORD lpFileSystemFlags, // 返回文件系统的标志,见下表
LPTSTR lpFileSystemNameBuffer, //
返回文件系统的名字(FAT,HPFS,NTFS或CDFS)
DWORD nFileSystemNameSize); // 文件系统名字缓冲区的最大尺寸
标志 含义
FS_CASE_IS_PRESERVED 当名字存入磁盘时文件名大小写保留下来
FS_CASE_SENSITIVE 文件系统支持大小写敏感文件名查询
FS_UNICODE_STORED_ON_DISK 文件系统支持磁盘上的文件名使用Unicode
FS_PERSISTENT_ACLS 文件系统维护和增强访问控制表(只在NTFS下)
GetDiskFreeSpace函数:
BOOL GetDiskFreeSpace(LPTSTR lpszRootPathName,// 逻辑驱动器的相关根目录
LPDWORD lpSectorsPerCluster, // 每簇多少扇区
LPDWORD lpBytesPerSector, // 每扇区多少字节
LPDWORD lpFreeClusters, // 空闲扇区数量
LPDWORD lpClusters); // 总扇区数量
DeviceIoControl函数:
BOOL DeviceIoControl(HANDLE hDevice, // 磁盘设备的句柄
DWORD dwIoControlCode,// 设备命令
LPVOID lpvInBuffer,DWORD cbInBuffer,LPVOID lpvOutBuffer,DWORD cbOutBuffer,
LPDWORD lpcbBytesReturned,LPOVERLAPPED lpOverlapped);
该函数用来直接向磁盘设备驱动程序发明令或请求信息.
hDevice参数指定一个磁盘设备的句柄.这个句柄可以调用函数CreateFile而得到.如果你
想获得指向一个软盘驱动器或一个硬盘驱动器的单个分区的句柄,按如下形式调用
CreateFile:
hDevice=CreateFile("///.//X:",/* X 代表设备的驱动器字母
*/0,FILE_SHARE_WRITE,
NULL,OPEN_EXISTING,0,NULL);
你也可以通过以下形式调用CreateFile来获得指向一个物理硬盘的句柄:
hDevice=CreateFile("///.//PhysicalDriveN",/*
N代表用户系统上的一个硬盘,系统第
一硬盘是驱动器0 */0,FIEL_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
dwIoControlCode参数指定想送给设备的命令,取以下值:
命令标识符 含义
FSCTL_DISMOUNT_VOLUME 卸下磁盘
FSCTL_LOCK_VOLUME 锁住磁盘
FSCTL_UNLOCK_VOLUME 解锁磁盘
IOCTL_DISK_CHECK_VERIFY 检查一个可拆除介质设备的变化
IOCTL_DISK_EJECT_MEDIA 从一个SCSI设备中弹出介质
IOCTL_DISK__FORMAT_TRACKS 格式化一个连续的磁道集
IOCTL_DISK_GET_DRIVE_GEOMETRY 获得物理磁盘的几何信息
IOCTL_DISK_GET_DRIVE_LAYOUT 提供关于磁盘上每一分区的信息
IOCTL_DISK_GET_MEDIA_TYPES 获得介质支持的信息
IOCTL_DISK_GET_PARTITION_INFO 获得磁盘分区的信息
IOCTL_DISK_LOAD_MEDIA 装介质进入设备
IOCTL_DISK_MEDIA_REMOVAL 允许或禁止介质弹出机制
IOCTL_DISK_PERFORMANCE 提供磁盘性能信息
IOCTL_DISK_REASSIGN_BLOCKS 映射磁盘块到空闲池地(spare_block_pool)
IOCTL_DISK_SET_DRIVE_LAYOUT 给磁盘分区
IOCTL_DISK_SET_PARTITION_INFO 设置磁盘分区类型
IOCTL_DISK_VERIFY 对一个磁盘区域进行逻辑格式化
IOCTL_SERIAL_LSRMST_INSERT 允许或禁止线和调制解调器状态数据进
入数据流
剩下的参数的含义依赖于你在dwIoControlCode参数中所传的操作:例如,如果你想格式化
磁道,你必须分配并初始化一个FORMAT_PARAMETERS结构:
typedef struct _FORMAT_PARAMETERS{
MEDIA_TYPE MediaType;
DWORD StartCylinderNumber;
DWORD EndCylinderNumber;
DWORD StartHeadNumber;
DWORD EndHeadNumber;
} FORMAT_PARAMETERS;
并且将这个结构的地址传给lpvInBuffer参数,将这个结构的大小传给cbInBuffer参数.
如果你想得到一个磁盘的几何信息,你必须分配一个DISK_GEOMETRY结构:
typedef struct _DISK_GEOMETRY{
MEDIA_TYPE MediaType;
LARGE_INTEGER Cylinders;
DWORD TracksPerCylinder;
DWORD SectorsPerTrack;
DWORD BytesPerSector;
} DISK_GEOMETRY;
并且将这个结构的地址传给lpvInBuffer参数,将这个结构的大小传给cbInBuffer参数.
目录操作
GetCurrentDirectory函数:
DWORD GetCurrentDirectory(DWORD cchCurDir, // 目录缓冲区的最大字符数
LPTSTR lpszCurDir); // 返回进程的当前路径
函数返回0,表示调用失败.否则,返回添装路径所需的字符数.
SetCurrentDirectory函数:
BOOL SetCurrentDirectory(LPTSTR lpszCurDir);
GetSystemDirectory函数获得系统目录:
UINT GetSystemDirectory(LPTSTR lpszSysPath,UINT cchSysPath);
GetWindowsDirectory函数获得Windows目录:
UINT GetWindowsDirectory(LPTSTR lpszWinPath,UINT cchWinPath);
CreateDirectory函数创建一个目录:
BOOL CreateDirectory(LPTSTR lpszPath,LPSECURITY_ATTRIBUTES lpsa);
RemoveDirectory函数删除一个目录:
BOOL RemoveDirectory(LPTSTR lpszDir);
拷贝、删除、移动及改名文件
CopyFile函数:
BOOL CopyFile(LPTSTR lpszExistingFile,LPTSTR lpszNewFile,BOOL
fFailIfExists);
DeleteFile函数:
BOOL DeleteFile(LPTSTR lpszFileName);
MoveFile和MoveFileEx函数:
BOOL MoveFile(LPTSTR lpszExisting,LPTSTR lpszNew);
BOOL MoveFileEx(LPTSTR lpszExisting,LPTSTR lpszNew, //
为NULL时删除一个文件
DWORD fdwFlags); // 取以下值:MOVEFILE_REPLACE_EXISTING、
MOVEFILE_COPY_ALLOWED、MOVEFILE_DELAY_UNTIL_REBOOT.
这两个函数还可以用于改名子目录和文件:
MoveFile("c://UTILITY","c://TOOLS");
MoveFile("c://WINNT//clock.exe","c://WINNT//watch.exe");
创建、打开和关闭文件
CreateFile函数:
HANDLE CreateFile(LPTSTR lpszName,DWORD fdwAccess,DWORD fdwShareMode,
LPSECURITY_ATTRIBUTES lpsa,DWORD fdwCreate,DWORD
fdwAttrsAndFlags,HANDLE hTemplateFile);
lpsa参数:指定文件具有的访问权限结构,目前只有NTFS文件系统支持这种能力.
fdwCreate参数:
标识符 含义
CREATE_NEW 创建一个新文件且若文件已经存在则失败
CREATE_ALWAYS 无论是否存在都创建一个新文件.如果以存在则覆盖它
OPEN_EXISTING 打开一个以存在的文件且若该文件已经存在则失败
OPEN_ALWAYS 如果文件存在则打开它否则就创建它
TRUNCATE_EXISTING 打开一个已存在的文件并将他的大小置为零,如果文件不存在则
失败
fdwAttrsAndFlags参数:包括文件属性和创建标志两个部分.当打开一个已存在的文件时,
属性信息将被忽略.
文件属性:
标识符 含义
FILE_ATTRIBUTE_ARCHIVE 存档文件.标记该文件用于备份或删除.当CreateFile
产生一个新文件时,该标记自动被设置
FILE_ATTRIBUTE_HIDDEN 隐藏文件
FILE_ATTRIBUTE_NORMAL 没有设置其他属性集.只能单独使用
FILE_ATTRIBUTE_READONLY 只读文件
FILE_ATTRIBUTE_SYSTEM 系统文件
FILE_ATTRIBUTE_TEMPORARY 临时文件
创建标志:
标识符 含义
FILE_FLAG_RANDOM_ACCESS 暗示系统你将随机地访问文件
FILE_FLAG_SEQUENTIAL_SCAN 暗示系统你将顺序地访问文件
FILE_FLAG_WRITE_THROUGH 使缓冲区无效以便使数据丢失的可能性减为最小
FILE_FLAG_DELETE_ON_CLOSE 文件关闭后自动删除文件
FILE_FLAG_BACKUP_SEMANTICS 在打开或生成文件任何文件时,系统一般执行安全
检查来确证试图打开或生成一个文件的进程拥有所
要求的访问权限.然儿,备份或恢复软件可以越过特
定的文件安全检查,并且只允许执行备份或恢复.
FILE_FLAG_POSIX_SEMANTICS 使用POSIX规则来访问一个文件,该规则使用的文件
系统允许大小写敏感文件名
FILE_FLAG_OVERLAPPED 异步访问文件(Windows 95没有实现)
hTemplateFile参数:标识一个文件句柄或NULL.如果标识一个文件句柄,则CreateFile函
数将忽略fdwAttrsAndFlags参数而使用由hTemplateFile所标识的文件的属性和标志
(hTemplateFile标识的文件必须使用GENERIC_READ标志打开),如果CreateFile正在打开
一个已存在的文件则该标志被忽略.
同步读写文件
ReadFile函数:
BOOL ReadFile(HANDLE hFile,LPVOID lpBuffer,DWORD nNumberToRead,LPDWORD
lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped);
WriteFile函数:
BOOL WriteFile(HANDLE hFile,CONST VOID *lpBuffer,DWORD
nNumberOfBytesToWrite,
LPWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverLapped);
定位文件指针
SetFilePointer函数:
DWORD SetFilePointer(HANDLE hFile,
LONG lDistanceToMove, // 你想移动指针的字节数
PLONG lpDistanceToMoveHigh, //
你想移动指针字节数的高32位值和返回以前的文
件指针指针位置的高32位值
DWORD dwMoveMethod); // 指定移动的开始点,见下表:
标识符 含义
FILE_BEGIN 文件头
FILE_CURRENT 当前位置
FILE_END 文件尾
函数返回文件的以前位置的低32位值.如果没能改变文件的指针,则返回0xFFFFFFFF并且
lpDistanceToMoveHigh缓冲区的内容将包含NULL.由于大文件完全有可能被成功地置于
0xFFFFFFFF,应此最好通过调用GetLastError检查是否返回NO_ERROR来确定函数调用成功
了.
设置文件尾
SetEndOfFile函数:
BOOL SetEndOfFile(HANDLE hFile);
该函数改变一个文件的长度,以使由文件指针标明的值成为文件的长度.
强制缓冲的数据写入磁盘
FlushFileBuffers函数:
BOOL FlushFileBuffers(HANDLE hFile);
所定及解锁文件的某区域
LockFile函数:
BOOL LockFile(HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
DWORD cbLockLow,DWORD cbLockHigh);
注意:不可以锁定一个包含某已所定的区域的区域.
UnlockFile函数;
BOOL UnlockFile(HANDLE hFile,DWORD dwFileOffsetLow,DWORD dwFileOffsetHigh,
DWORD cbUnlockLow,DWORD cbUnlockHigh);
注意:解锁函数的调用要和锁定函数调用一一对应.
在你关闭文件或结束进程之前必须解锁所有锁定的区域.
LockFileEx函数:
BOOL LockFileEx(HANDLE hFile,DWORD dwFlags,DWORD dwReserved,DWORD
nNumberOfBytesToLockLow,DWORD nNumberBytesToLockHigh,LPOVERLAPPED
lpOverlapped);
dwFlags参数:缺省情况下,申请一个共享锁(允许其它进程可以从锁定的区域读数据)或使
用LOCKFILE_EXCLUSIVE_LOCK标志来申请一个排他锁(LockFile在调用LockFileEx使用了
该标志)
lpOverlapped参数:指向一个OVERLAPPED结构:
typedef struct _OVERLAPPED{
DWORD Internal;
DWORD InternalHigh;
DWORD Offset; // 锁定区域的开始字节(低32位)
DWORD OffsetHigh; // 锁定区域的开始字节(高32位)
HANDLE hEvent;
} OVERLAPPED;
typedef OVERLAPPED *LPOVERLAPPED;
UnlockFileEx函数:
UnlockFileEx( HANDLE hFile,DWORD dwReserved,DWORD
nNumberOfBytesToUnlockLow,
DWORD nNumberBytesToUnlockHigh,LPOVERLAPPED lpOverlapped);
注:windows 95没有实现上述两个函数.
异步读写文件
windows 95 没有实现!
操作文件属性
文件标志:
GetFileAttributes函数:
DWORD GetFileAttributes(LPTSTR lpszFileName);
该函数返回lpszFileName标识的文件的属性(FILE_ATTRIBUTE_ARCHIVE、
FILE_ATTRIBUTE_DIRECTORY、FILE_ATTRIBUTE_HIDDEN、FILE_ATTRIBUTE_NORMAL、
FILE_ATTRIBUTE_READONLY、FILE_ATTRIBUTE_SYSTEM)
SetFileAttributes函数:
BOOL SetFileAttributes(LPTSTR lpFileName,DWORD dwFileAttributes);
如下面的代码,去掉CALC.exe文件的存档属性:
DWORD dwFileAttributes=GetFileAttributes("CALC.exe");
dwFileAttributes &=~FILE_ATTRIBUTE_ARCHIVE;
SetFileAttributes(dwFileAttributes);
文件大小
GetFileSize函数:
DWORD GetFileSize(HANDLE hFile,LPDWORD lpdwFileSizeHigh);
文件时间戳
GetFileTime函数:
BOOL GetFileTime(HANDLE hFile,LPFILETIME lpftCreation,LPFILETIME
lpftLastAccess,LPFILETIME lpftLastWrite);
typedef struct _FILETIME{
DWORD dwLowDataTime;
DWORD dwHighDataTime;
} FILETIME, * PFILETIME, *LPFILETIME;
在FILETIME结构中的64位值反映了从1601年1月1日以来的毫秒数.
操作FILETIME的辅助函数:
时间比较:
LONG CompareFileTime(LPFILETIME lpft1,LPFILETIME lpft2);
该函数将返回下列整数值:
CompareFileTime的结果 含义
-1 lpft1比lpft2小(老)
0 lpft1与lpft2(年龄)相等
1 lpft1比lpft2大(年轻)
把文件时间转变为系统时间或反过来:
BOOL FileTimeToSystemTime(LPFILETIME lpft,LPSYSTEMTIME lpst);
BOOL SystemTimeToFileTime(LPSYSTEMTIME lpst,LPFILETIME lpft);
SYSTEMTIME的结构如下所示:
typedef struct _SYSTEMTIME{
WORD wYear;
WORD wMonth;
WORD wDayOfWeek; // 如果从系统时间转变到文件时间该成员将被忽略
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;
将文件时间转变为当地时间或反之:
BOOL FileTimeToLocalFileTime(LPFILETIME lpft,LPFILETIME lpftLocal);
BOOL LocalFileTimeToFileTime(LPFILETIME lpftLocal,LPFILETIME lpft);
注意:不能将一个相同的地址同时作为两个参数
转换FILETIME结构为MS-DOS所用的时间格式或反之:
BOOL FileTimeToDosDataTime(LPFILETIME lpft,LPWORD
lpwDOSData/*日期*/,LPWORD
lpwDOSTime/*时间*/);
BOOL DosDataTimeToFileTime(WORD wDOSData,WORD wDOSTime,LPFILETIME lpft);
对于Windows 95,这两个函数被允许直到2099年12月31号;对Windows
NT,被允许直到20
17年12月31号.
SetFileTime函数改变文件时间与文件的联系:
BOOL SetFileTime(HANDLE hFile,LPFILETIME lpftCreation,LPFILETIME
lpftLastAccess,LPFILETIME lpftLastWrite);
GetFileInformationByHandle函数:
GetFileInformationByHandle(HANDLE hFile,LPBY_HANDLE_FILE_INFORMATION
lpFileInformation);
该文件将指定文件的信息保存在lpFileInformation地址指定的
BY_HANDLE_FILE_INFORMATION结构中:
typedef struct _BY_HANDLE_FILE_INFORMATION{
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD dwVolumeSericalNumber; // 文件所在的磁盘的序列号
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD nNumberOfLinks; // 链接的数目(在POSIX子系统中使用)
DWORD nFileIndexHigh; //
文件句柄的唯一ID.对于同一个文件,在不同的应用程序
中打开,其文件
DWORD nFileIndexLow; //
ID将会相同.一个应用程序可以使用文件ID与卷序列号
相连来判断两个(或多个)不同的文件句柄实际上是否指向同一个文件.
} BY_HANDLE_FILE_INFORMATION, *LPBY_HANDLE_FILE_INFORMATION;
搜寻文件
GetFullPathName函数:
DWORD GetFullPathName(LPCTSTR lpszFile, // 文件名或带有相关路径的文件名
DWORD cchPath, // 显示驱动器和路径按字符计算的缓冲区的大小
LPTSTR lpszPath, // 返回的当前驱动器和当前路径名计算出的文件的全路径名
LPTSTR * ppszFilePart); //
该函数将用文件名所在的lpszPath里的地址填充这个
变量.应用程序可以使用这个信息制作自己的标题.利用这个参数,可以得到文件名的地
址:
szFilePart=strchr(szPath,'//')+1;
SearchPath函数:
DWORD SearchPath(LPTSTR lpszPath,LPCTSTR lpszFile,LPCSTR
lpszExtension,DWORD
cchReturnBuffer,LPTSTR lpszReturnBuffer,LPTSTR *PlpszFilePart);
该函数在你指定的目录列表中寻找一个文件,你将需要扫描的路径列表传给参数
lpszPath.如果为NULL,则在下表中所列路径内寻找文件:
(1) 装入应用程序的所在的目录
(2) 当前目录
(3) Windows 系统目录
(4) Windows 目录
(5) 在PATH环境变量中所列的目录
lpszFile参数指定要搜寻的文件,如果该参数包含一个扩展名,则应该传给
lpszExtension参数一个NULL值,否则,必须传给lpszExtension参数一个以点开头的扩展
名.
另一个查询文件的方法允许你遍历硬盘的每一个目录看你想看的文件.通过调用函数
FindFirstFile你告诉系统从哪一个目录开始寻找什么样的文件名:
HANDLE FindFirstFile(LPTSTR lpszSearchFile,LPWIN32_FIND_DATA lpffd);
lpszSearchFile参数:表示要查找文件名,可以使用通配符(*
?),并且可以带上开始路径.
lpffd参数:指向一个WIN32_FIND_DATA结构的地址:
typedef struct _WIN32_FIND_DATA{
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwReserved0;
DWORD dwReserved1;
CHAR cFileName[MAX_PATH];
CHAR cAlternateFileName[14]; // 文件的合成名(8.3文件名)
} WIN32_FIND_DATA, *PWIN32_FIND_DATA,*LPWIN32_FIND_DATA;
如果FindFirstFile在指定的目录中成功地找到了一个匹配的文件,它将填充
WIN32_FIND_DATA结构成员并返回一个文件句柄.如果匹配失败,则返回
INVALID_HANDLE_VALUE,并且不改变结构内容.
GetShortPathName函数将指定的长文件名转变为短文件名:
DWORD GetShortPathName(LPCTSTR lpszLongPath,LPTSTR lpszShortPath,
DWORD cchBuffer);
如果FindFirstFile已经成功地找到匹配文件,你可以调用FindNextFile来找到下一个
匹配的文件:
BOOL FindNextFile(HANDLE hFindFile,LPWIN32_FIND_DATA lpffd);
在你结束上述搜寻文件操作,你必须调用FindClose函数来关闭由FindFirstFile返回的句
柄:
BOOL FindClose(HANDLE hFindFile);
文件系统变化通知
首先,你的应用程序调用FindFirstChangeNotification来告诉系统你对文件系统的变化
有兴趣:
HANDLE FindFirstChangeNotification(LPTSTR lpszPath,BOOL
fWatchSubTree,DWORD
fdwFilter);
lpszPath参数:指定你想监视的目录树的根(可以为子目录).
fWatchSubTree参数:告诉系统你是否想看发生在lpszPath目录下属目录的事件.
fdwFilter参数:告诉系统你对什么类型的文件变化有兴趣:
标志 含义
FILE_NOTIFY_CHANGE_FILE_NAME 文件被创建、改名、或删除
FILE_NOTIFY_CHANGE_DIR_NAME 目录被创建、改名、或删除
FILE_NOTIFY_CHANGE_ATTRIBUTES 文件属性改变
FILE_NOTIFY_CHANGE_SIZE 文件大小变化
FILE_NOTIFY_CHANGE_LAST_WRITE 文件最近写入时间变化
FILE_NOTIFY_CHANGE_SECURITY 目录或文件的安全描述被改变
如果该函数执行成功,返回一个同步事件句柄(文件通知,相似于人工重置事件),如果
错误则返回INVALID_HANDLE_VALUE.
当文件变化通知有了信号,你的线程被唤醒,并可以做任何想做的事情(漫游驱动器的目录
树),当你结束时,必须调用FindNextChangeNotification函数:
BOOL FindNextNotification(HANDLE hChange);
将文件变化通知置成无信号状态(类似调用ResetEvent).当你在漫游驱动器目录树时,可
能命令外壳线程已经产生了更多的文件变化通知,对FindNextChangeNotification函数的
调用检查这种情况是否已经发生,若是在对象发出信号之前发生,那么对象将不被置成无
信号状态而是保持有信号状态.这样,如果你的线程在次等待,将马上满足条件.
当你不需要文件变化通知时,应该调用FindCloseChangeNotification关闭它:
BOOL FindCloseChangeNotification(HANDLE hChange);