LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

谁动了我的文件?Windows 下文件操作监控完全指南(C# + C++)

admin
2026年2月25日 16:4 本文热度 173

最近在做虚拟打印机时,需要实时监控打印文件的到达,并移动文件到另外的位置。一开始我使用了线程,在线程里去检测新文件的到达。实际上Windows提供了一个文件监控接口函数ReadDIrectoryChangesW。这个函数可以对所有文件操作进行监控。

 

ReadDirectoryChangesW

函数声明

BOOL ReadDirectoryChangesW(  [in]                HANDLE                          hDirectory,  [out]               LPVOID                          lpBuffer,  [in]                DWORD                           nBufferLength,  [in]                BOOL                            bWatchSubtree,  [in]                DWORD                           dwNotifyFilter,  [out, optional]     LPDWORD                         lpBytesReturned,  [in, out, optional] LPOVERLAPPED                    lpOverlapped,  [in, optional]      LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);

参数

hDirectory

指向要监听的目录句柄,必须使用FILE_LIST_DIRECTORY访问权限打开此目录。

 

lpBuffer

指向要读取DWORD对齐结果的格式化缓冲区的指针。该缓冲区的结构由FILE_NOTIFY_INFORMATION结构定义

 

nBufferLength

lpBuffer参数指向的缓冲区大小

 

bWatchSubtree

 指示是否以指定目录为根目录进行监控。

True:监视以指定目录为根的目录树

FALSE:仅监视指定目录

 

dwNotifyFilter

检查函数以确定等待操作是否满足过滤条件。此参数可以指定为以下的一个或多个

含义
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_LAST_ACCESS
监视目录或子树中文件最后访问时间的任何更改
FILE_NOTIFY_CHANGE_CREATION
监视目录或子树中文件创建时间的任何更改
FILE_NOTIFY_CHANGE_SECURITY
监视目录或子树中任何安全描述符更改

 

lpBytesReturned

对于同步调用,此参数接收传输到lpBuffer参数中的字节数

 

lpOverlapped

指向OVERLAPPED结构的指针,提供在异步操作期间要用的数据,否则该值为NULL

 

lpConpletionRoutine

指向完成例程的指针,当操作已经完成或取消,并且调用线程处于可警告的等待状态时才会调用它

 

返回值

成功:不为0

失败:0

 

监控指定目录下的文件创建

假设我这里要监控D:\PrintFiles目录下的文件更改,操作如下:

打开目录,获取文件句柄

// 打开目录, 获取文件句柄    HANDLE hDirectory = ::CreateFile(L"D:\\PrintFiles", FILE_LIST_DIRECTORY,        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,        FILE_FLAG_BACKUP_SEMANTICS, NULL);    if (INVALID_HANDLE_VALUE == hDirectory)    {        return 0;    }

 

调用ReadDirectoryChangesW监控文件夹

我这里只演示同步调用,异步调用可以参考MSDN文档。同步调用时,如果监控的目录未发生更改,会一直阻塞在那里。

 

    DWORD dwRet = 0;    DWORD dwBufferSize = 2048;
    BYTE* pBuf = new BYTE[dwBufferSize];    FILE_NOTIFY_INFORMATION* pFileNotifyInfo = (FILE_NOTIFY_INFORMATION*)pBuf;
    BOOL bRet = ReadDirectoryChangesW(hDirectory,        pFileNotifyInfo,        dwBufferSize,        TRUE,        FILE_NOTIFY_CHANGE_FILE_NAME|           //修改文件名        FILE_NOTIFY_CHANGE_ATTRIBUTES |         // 修改文件属性        FILE_NOTIFY_CHANGE_LAST_WRITE,          // 最后一次写入        &dwRet,        NULL, NULL);

输出结果

if (FALSE == bRet)    {        DWORD dwError = GetLastError();        std::cout << "ReadDirectoryChangesW failed - " << dwError << std::endl;    }
    std::wcout.imbue(std::locale("chs"));
    //判断操作类型    switch (pFileNotifyInfo->Action)    {    case FILE_ACTION_ADDED:         std::wcout << "Create file " << pFileNotifyInfo->FileName << std::endl;        break;    default:        break;    }
    CloseHandle(hDirectory);    delete[] pBuf;

 

运行效果

 

System.IO.FileSystemWatcher类

在C#中,可以使用 System.IO.FileSystemWatcher类来进行监听。它内部也是调用了ReadDirectoryChangesW API函数

监控文件的行为定义在System.IO.NotifyFilters

[Flags]    public enum NotifyFilters    {        FileName = 0x1,        DirectoryName = 0x2,        Attributes = 0x4,        Size = 0x8,        LastWrite = 0x10,        LastAccess = 0x20,        CreationTime = 0x40,        Security = 0x100    }

 

在C#中是通过事件订阅的形式来进行通知的

C#进行了再次封装,所以会比直接在C++中使用要方便一些。创建监听后,只需要等待事件触发就行了。

 

FileSystemWatcher使用方法如下:

FileSystemWatcher systemWatcher = new FileSystemWatcher();systemWatcher.Path = this.textBox1.Text;
//设置监听的行为//这里设置为文件名systemWatcher.NotifyFilter = NotifyFilters.FileName;
//设置文件类型过滤systemWatcher.Filter = "*.txt";
systemWatcher.Changed += (obj, args) => { ShowMsg($"文件更改{args.Name}"); };systemWatcher.Created += (obj, args) => { ShowMsg($"文件创建{args.Name}"); };systemWatcher.Deleted += (obj, args) => { ShowMsg($"文件删除{args.Name}"); };systemWatcher.Renamed += (obj, args) => { ShowMsg($"文件重命名{args.Name}"); };
//开始监听systemWatcher.EnableRaisingEvents = true;

 

运行效果

 

示例代码

https://github.com/zhaotianff/cnblog-demo-code/tree/main/MonitorFile

 

参考资料:

https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-readdirectorychangesw?redirectedfrom=MSDN


阅读原文:https://mp.weixin.qq.com/s/IRPkcNy55uUZIWRFCP7eQA


该文章在 2026/2/25 16:04:24 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved