.NET : 使用ReadDirectoryChangesW监控文件夹的变化

近日在讨论到之前我发布的“文件同步工具”时,有朋友建议用ReadDirectoryChangesW方法去做监控。我个人觉得,如果在C#中做监控的话,首选还是.NET Framework封装好的FileSystemWatcher去做。但我以为,监控也有监控的烦恼,就是说要一直监控。而一旦中途停止监控,又自然会涉及到一个状态保存的问题。

我刚才将该函数看了一下,做了一个范例,如下。如果有兴趣的朋友,可以参考一下

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode,
  IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes,
  IntPtr hTemplateFile);

[DllImport("kernel32.dll")]
static extern bool CloseHandle(IntPtr hObject);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
static extern bool ReadDirectoryChangesW(IntPtr hDirectory, IntPtr lpBuffer, uint nBufferLength,
  bool bWatchSubtree, uint dwNotifyFilter, out uint lpBytesReturned, IntPtr lpOverlapped,
  IntPtr lpCompletionRoutine);

static void Main(string[] args)
{

    const uint FILE_LIST_DIRECTORY = 0x1;
    const uint FILE_SHARE_READ = 0x1;
    const uint FILE_SHARE_WRITE = 0x2;
    const uint FILE_SHARE_DELETE = 0x4;
    const uint OPEN_EXISTING = 3;
    const uint FILE_FLAG_BACKUP_SEMANTICS = 0x2000000;
    const uint FILE_NOTIFY_CHANGE_FILE_NAME = 0x1;
    const uint FILE_NOTIFY_CHANGE_DIR_NAME = 0x2;
    const uint FILE_NOTIFY_CHANGE_LAST_WRITE = 0x10;

    const uint BUFSIZE = 2048;
    string myDocs = @"E:\Temp";
    Console.WriteLine("Monitoring name changes in {0} and subdirectories.", myDocs);

    IntPtr hDir = CreateFile(myDocs, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE |
      FILE_SHARE_DELETE, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero);
    if (hDir == IntPtr.Zero)
    {
        Console.WriteLine("CreateFile failed. " + Marshal.GetLastWin32Error());
        return;
    }

    IntPtr pBuf = IntPtr.Zero;
    try
    {
        pBuf = Marshal.AllocHGlobal((int)BUFSIZE);
        uint bytesReturned;
        while (ReadDirectoryChangesW(hDir, pBuf, BUFSIZE, true, FILE_NOTIFY_CHANGE_FILE_NAME |
               FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, out bytesReturned,
               IntPtr.Zero, IntPtr.Zero))
        {
            string[] actions = new string[] { "(unknown action) ", "Added ", "Removed ",
                              "Modified ", "Old name ", "New name " };
            IntPtr pCurrent = pBuf;
            while (pCurrent != IntPtr.Zero)
            {
                // Read file length (in bytes) at offset 8
                int fileLen = Marshal.ReadInt32(pCurrent, 8);
                // Read file name (fileLen/2 characters) from offset 12
                string file = Marshal.PtrToStringUni((IntPtr)(12 + (int)pCurrent), fileLen / 2);
                // Read action at offset 4
                int action = Marshal.ReadInt32(pCurrent, 4);
                if (action < 1 || action >= actions.Length) action = 0;
                Console.WriteLine(actions[action] + file);

                // Read NextEntryOffset at offset 0 and move pointer to next structure if needed
                int inc = Marshal.ReadInt32(pCurrent);
                pCurrent = inc != 0 ? (IntPtr)(inc + (int)pCurrent) : IntPtr.Zero;
            }
        }
        //else
            //Console.WriteLine("ReadDirectoryChangesW failed. " + Marshal.GetLastWin32Error());
    }
    finally
    {
        if (pBuf != IntPtr.Zero) Marshal.FreeHGlobal(pBuf);
        CloseHandle(hDir);
    }

    Console.Read();
}

本文由作者:陈希章 于 2009/8/9 8:06:22 发布在:博客园,转载请注明出处
posted @ 2009-08-09 08:06  陈希章  阅读(2738)  评论(0编辑  收藏  举报