Chinaunix首页 | 论坛 | 博客
  • 博客访问: 9547451
  • 博文数量: 1227
  • 博客积分: 10026
  • 博客等级: 上将
  • 技术积分: 20273
  • 用 户 组: 普通用户
  • 注册时间: 2008-01-16 12:40
文章分类

全部博文(1227)

文章存档

2010年(1)

2008年(1226)

我的朋友

分类: C/C++

2008-03-14 14:12:04

下载本文示例代码
C# 中有类 FileSystemWatcher 不但能够知道指定目录树中的文件/目录的改变,而且能够知道是哪个文件/目录在改变,而我用FindFirstChangeNotification等Win API 却不能实现第二个功能,虚耗了不少时间,昨日在msdn中发现 ReadDirectoryChangesW 是可行的,特封装一下,请大家斧正。
// 名称: FileSystemWatcher
// 功能: 监测指定目录中的文件/目录的改变
// 环境要求: Requires Windows NT 3.51 SP3 or later, and Unsupported Windows 95/98.
// 版权申明: 可任意拷贝、修改、发布
// 作者: 周星星
// 日期: 2003-08-07
// 说明: 未做测试
// VCKBASE.COM

#define _WIN32_WINNT 0x0500

#include 
#include 
#include 

enum ACTION { ADDED=1, REMOVED=2, MODIFIED=3, RENAMED=4 };
class FileSystemWatcher
{
public:
    typedef void (__stdcall *LPDEALFUNCTION)( ACTION act, std::string filename1, std::string filename2 );

    bool Run( std::string path, LPDEALFUNCTION dealfun )
    {
        WatchedDir = path;
        DealFun = dealfun;

        DWORD ThreadId;
        hThread=CreateThread( NULL,0,Routine,this,0,&ThreadId );
        return NULL!=hThread;
    }
    void Close()
    {
        if( NULL != hThread )
        {
            TerminateThread( hThread, 0 );
            hThread = NULL;
        }
        if( INVALID_HANDLE_VALUE != hDir )
        {
            CloseHandle( hDir );
            hDir = INVALID_HANDLE_VALUE;
        }
    }
    FileSystemWatcher() : DealFun(NULL), hThread(NULL), hDir(INVALID_HANDLE_VALUE)
    {
    }
    ~FileSystemWatcher()
    {
        Close();
    }

private:
    std::string WatchedDir;
    LPDEALFUNCTION DealFun;
    HANDLE hThread;
    HANDLE hDir;
private:
    FileSystemWatcher( const FileSystemWatcher& );
    FileSystemWatcher operator=( const FileSystemWatcher );
private:
    static DWORD WINAPI Routine( LPVOID lParam )
    {
        FileSystemWatcher* obj = (FileSystemWatcher*)lParam;

        obj->hDir = CreateFile(
            obj->WatchedDir.c_str(),
            GENERIC_READ|GENERIC_WRITE,
            FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
            NULL,
            OPEN_EXISTING,
            FILE_FLAG_BACKUP_SEMANTICS,
            NULL
        );
        if( INVALID_HANDLE_VALUE == obj->hDir ) return false;

        char buf[ 2*(sizeof(FILE_NOTIFY_INFORMATION)+MAX_PATH) ];
        FILE_NOTIFY_INFORMATION* pNotify=(FILE_NOTIFY_INFORMATION *)buf;
        DWORD BytesReturned;
        while(true)
        {
            if( ReadDirectoryChangesW( obj->hDir,
                pNotify,
                sizeof(buf),
                true,
                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,
                &BytesReturned,
                NULL,
                NULL ) )
            {
                char tmp[MAX_PATH], str1[MAX_PATH], str2[MAX_PATH];
                memset( tmp, 0, sizeof(tmp) );
                WideCharToMultiByte( CP_ACP,0,pNotify->FileName,pNotify->FileNameLength/2,tmp,99,NULL,NULL );
                strcpy( str1, tmp );

                if( 0 != pNotify->NextEntryOffset )
                {
                    PFILE_NOTIFY_INFORMATION p = (PFILE_NOTIFY_INFORMATION)((char*)pNotify+pNotify->NextEntryOffset);
                    memset( tmp, 0, sizeof(tmp) );
                    WideCharToMultiByte( CP_ACP,0,p->FileName,p->FileNameLength/2,tmp,99,NULL,NULL );
                    strcpy( str2, tmp );
                }

                obj->DealFun( (ACTION)pNotify->Action, str1, str2 );
            }
            else
            {
                break;
            }
        }

        return 0;
    }
};
以下是测试代码
#include 
#include 
using namespace std;

void __stdcall MyDeal( ACTION act, std::string filename1, std::string filename2 )
{
    switch( act )
    {
    case ADDED:
        cout << "Added    - " << filename1 << endl;
        break;
    case REMOVED:
        cout << "Removed  - " << filename1 << endl;
        break;
    case MODIFIED:
        cout << "Modified - " << filename1 << endl;
        break;
    case RENAMED:
        cout << "Rename   - " << filename1 << " " << filename2 << endl;
        break;
    }
}

void main()
{
    FileSystemWatcher a;
    a.Run( "D:\\", MyDeal );

    cout << "Watch D:\\" << endl;
    cout << "Press  to quit." << endl;
    while(getch()!='q');

    a.Close();
}

  以上代码在 Win2K + VC++6.0 中调试通过,写在同一个文件中是为了调试方便,正式使用时最好能拆分成h文件和cpp文件;  我本想既支持Ansi编码又支持Unicode,但后来心情浮躁,就懒得写了,甚至也没有做足够的测试,所以这段代码写得是很差的,但我实在不想再写了,只想睡觉,所以贴出来抛砖引玉,希望诸位能将修正后的代码贴上来。

下载本文示例代码
阅读(1591) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~