如何监控目录里文件的添加修改删除

wufan110 2008-10-30 05:31:56
如何监控目录里文件的添加修改删除
...全文
1315 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
KTNQSJW 2008-11-02
  • 打赏
  • 举报
回复
//在自已的程序中监控当然可以
//但是在自已的程序退出之后,要想
File Dictory 's Create\Write\Read
(1) MFC Funtion\
(2)Windows API
(3)自写函数
wufan110 2008-11-01
  • 打赏
  • 举报
回复
为什么我改一个文件内容,会出现两次
还有如果我改了子目录。为什么只能获取子目录名?
UINT MyThreadProc( LPVOID pParam )
{
::CtestDirDlg *PWnd=(CtestDirDlg*)pParam;
HANDLE hDir=CreateFile(_T("D:\\arswp"),GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_DELETE,
NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
if(INVALID_HANDLE_VALUE==hDir)
{
PWnd->MessageBox("指定的文件目录不存在!");
}
else
{
char buf[50*sizeof(FILE_NOTIFY_INFORMATION)+MAX_PATH];
::FILE_NOTIFY_INFORMATION * pNotify=(FILE_NOTIFY_INFORMATION*)buf;
DWORD BytesReturned;
while(true)
{
if(ReadDirectoryChangesW(hDir,pNotify,sizeof(buf),true,
FILE_NOTIFY_CHANGE_LAST_WRITE,//FILE_NOTIFY_CHANGE_CREATION|
&BytesReturned,NULL,NULL))
{
char tmp[MAX_PATH],str1[MAX_PATH],str2[MAX_PATH];
memset(tmp,0,sizeof(tmp));
bool hasNext=true;
do{
WideCharToMultiByte(CP_ACP,0,pNotify->FileName,pNotify->FileNameLength/2,tmp,99,NULL,NULL);
strcpy(str1,tmp);
::CEdit* pEdit=(::CEdit*)PWnd->GetDlgItem(IDC_EDIT1);

CString str;
pEdit->GetWindowText(str);
str=str+"\r\n"+str1;
pEdit->SetWindowText(str);
if(pNotify->NextEntryOffset>0)
{
hasNext=true;
}
else
{
hasNext=false;
}
pNotify=(FILE_NOTIFY_INFORMATION*)((char*)pNotify+pNotify->NextEntryOffset);
}while(pNotify->NextEntryOffset>0);
}
}
}
return 0;
}
BOOL CtestDirDlg::OnInitDialog()
{
CDialog::OnInitDialog();

// 将“关于...”菜单项添加到系统菜单中。

// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}

// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标

AfxBeginThread(MyThreadProc,this);
// TODO: 在此添加额外的初始化代码

return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
为什么我改一个文件内容,会出现两次
还有如果我改了子目录。为什么只能获取子目录名?
hustzcj 2008-11-01
  • 打赏
  • 举报
回复
mark
wufan110 2008-11-01
  • 打赏
  • 举报
回复
真的没办法么?
jimmyhappy 2008-10-31
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 wufan110 的回复:]
我想再请教个问题。
lpBuffer,应该为多大呢?
1个字节,100个字节?还是多少呢?
[/Quote]

windows最长文件名是多少???
wufan110 2008-10-31
  • 打赏
  • 举报
回复
为什么?
还有如果我改了子目录。为什么只能获取子目录名?
wufan110 2008-10-31
  • 打赏
  • 举报
回复
http://www.soft000.com/down/testDir.rar
谁帮我看看,这样写行吗?
为什么我改一个文件内容,会出现两次
wufan110 2008-10-30
  • 打赏
  • 举报
回复
我想再请教个问题。
lpBuffer,应该为多大呢?
1个字节,100个字节?还是多少呢?
jimmyhappy 2008-10-30
  • 打赏
  • 举报
回复
Windows里面对目录、文件监控提供了两个API,它们分别是:FindFirstChangeNotification和ReadDirectoryChangesW。
1、FindFirstChangeNotification
HANDLE FindFirstChangeNotification(
LPCTSTR lpPathName,
BOOL bWatchSubtree,
DWORD dwNotifyFilter
);

该API能够监控文件名、目录名、文件属性、子文件夹、文件大小、文件的最后写时间、安全属性的改变。该函数返回的是一个监控句柄(Notification Handle),该句柄能够被 WaitForMultipleObjects 其上进行等待,当该句柄所监控的条件满足时,该句柄就会处于激发状态,这时用户程序就能够知道该目录发生了变化。在进行了用户自己的处理之后,一定要调用BOOL FindNextChangeNotification(HANDLE hChangeHandle)来将该监控句柄置为去激活状态,并继续等待下一次被激活。如果你不再想监控了,就要调用FindCloseChangeNotification关闭监控句柄。

下面是MSDN上的一个例子:

**********************FindFirstChangeNotification********************
DWORD dwWaitStatus;
HANDLE dwChangeHandles[2];

// Watch the C:\WINDOWS directory for file creation and
// deletion.

dwChangeHandles[0] = FindFirstChangeNotification(
"C:\\WINDOWS", // directory to watch
FALSE, // do not watch the subtree
FILE_NOTIFY_CHANGE_FILE_NAME); // watch file name changes

if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)
ExitProcess(GetLastError());

// Watch the C:\ subtree for directory creation and
// deletion.

dwChangeHandles[1] = FindFirstChangeNotification(
"C:\\", // directory to watch
TRUE, // watch the subtree
FILE_NOTIFY_CHANGE_DIR_NAME); // watch dir. name changes

if (dwChangeHandles[1] == INVALID_HANDLE_VALUE)
ExitProcess(GetLastError());

// Change notification is set. Now wait on both notification
// handles and refresh accordingly.

while (TRUE)
{

// Wait for notification.

dwWaitStatus = WaitForMultipleObjects(2, dwChangeHandles,
FALSE, INFINITE);

switch (dwWaitStatus)
{
case WAIT_OBJECT_0:

// A file was created or deleted in C:\WINDOWS.
// Refresh this directory and restart the
// change notification. RefreshDirectory is an
// application-defined function.

RefreshDirectory("C:\\WINDOWS")
if ( FindNextChangeNotification(
dwChangeHandles[0]) == FALSE )
ExitProcess(GetLastError());
break;

case WAIT_OBJECT_0 + 1:

// A directory was created or deleted in C:\.
// Refresh the directory tree and restart the
// change notification. RefreshTree is an
// application-defined function.

RefreshTree("C:\\");
if (FindNextChangeNotification(
dwChangeHandles[1]) == FALSE)
ExitProcess(GetLastError());
break;

default:
ExitProcess(GetLastError());
}
}

*********************************************************************


2、ReadDirectoryChangesW
BOOL ReadDirectoryChangesW(
HANDLE hDirectory,
LPVOID lpBuffer,
DWORD nBufferLength,
BOOL bWatchSubtree,
DWORD dwNotifyFilter,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

这个函数的参数很多,但是在某种特定的使用场合下,通常不会用到全部的参数,也就前面的5个。

该函数提供了同步和异步的两大类方法,异步方法里面又有三种不同异步处理机制。(注意:这里所说的同步或异步指的是操作系统提供的同步或异步机制,在用户程序看来使用了操作系统同步机制的代码仍然可以是异步的。)

先来看看第一个参数hDirectory,从字面上看来是一个目录句柄,其实是一个文件句柄,在操作系统的眼里目录也只是一种特殊的文件,因此该句柄的获得需要调用CreateFile函数:


hDir = CreateFile(
DirName, // pointer to the file name
FILE_LIST_DIRECTORY, // access (read/write) mode 打开目录
FILE_SHARE_READ|FILE_SHARE_DELETE, // share mode
NULL, // security descriptor
OPEN_EXISTING, // how to create
FILE_FLAG_BACKUP_SEMANTICS, // file attributes 打开目录必须的选项
NULL // file with attributes to copy
);



知道了目录句柄如何获得的,就可以看看同步方式如何监控目录了。

首先我们浏览一下其他的参数,从最简单的布尔变量看起,bWatchSubtree一眼就能够看出是:是否监控子目录。OK,再看DWORD dwNotifyFilter这个参数肯定是目录变化通知过滤器了,查看MSDN文档知道修改文件名的过滤器选项就是FILE_NOTIFY_CHANGE_FILE_NAME,修改文件就是FILE_NOTIFY_CHANGE_LAST_WRITE,等等。
然 后要了解其他的参数有何意义就要先了解一下操作系统把目录变化通知是怎样交给用户代码的。通知是放在哪里?有些什么内容?它的内存是由谁分配的?如果是由 用户分配的(这是最自然的一种想法了),又是怎样告知操作系统的?好了,想到这里,我想第二、第三个参数的意义已经很明确了,用户代码就是通过这两个参数 来告知操作系统该把目录变化通知放在首地址为lpBuffer, 长度为nBufferLength的一块内存当中的。但是该内存又是怎样组织的呢?操作系统是把他们放在FILE_NOTIFY_INFORMATION这个结构里面的:


typedef struct _FILE_NOTIFY_INFORMATION {



DWORD NextEntryOffset;



DWORD Action;



DWORD FileNameLength;



WCHAR FileName[1];
} FILE_NOTIFY_INFORMATION, *PFILE_NOTIFY_INFORMATION;



有 经验的人可以很快看出这其实是一个链表结构,第一个字段存储了要获得下一个记录需要跳过多少字节数,如果它的值为0,就表示本记录已经是链表中的最后一条 记录了。该字段其实也可以看做是一个指向下一条记录的指针。第二个字段的含义是:本次通知了哪种类型的目录变化。第三个字段表示的是变化的文件或者目录的 名称的长度。第四个字段是一个Unicode字符数组的首地址。
哦,知道了目录变化通知是放在一个链表里面的,而且知道这个链表的首地址是lpBuffer,那么这个链表总共有多大呢?这个数值是放在LPDWORD lpBytesReturned参数里面的。
好了,同步监控所涉及到的参数就这么多了,那同步监控的具体步骤呢?很简单:

a) 使用CreateFile获取目录句柄
b) 在一个While循环里面调用ReadDirectoryChangesW,并且把自己分配的内存首地址、内存长度、目录句柄传给该函数。用户代码在该函数的调用中进行同步等待。
这样一旦有了目录变化,操作系统便会从对ReadDirectoryChangesW的调用中返回,并把目录变化通知放在了用户指定的位置。

16,548

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧