我可以在c ++中使用ReadDirectoryChangesW()来查看多个目录以进行更改吗?

时间:2017-12-06 05:28:44

标签: c++ windows winapi

我正在尝试使用ReadDirectoryChangesW监视不同的目录以进行更改,并且我成功使用它监视单个目录。但是当涉及到监视多个目录时,我遇到的问题是第一个目录被分配给句柄,它只在该目录中查找更改,然后只有在满足第一个目录条件时才会查看下一个目录。但我想同时观看多个目录。我可以帮我解决这个问题吗?

我附上以下代码供参考。

#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <vector>
#include <fstream>
#include <mutex>
#include "sys/stat.h"
#include <dirent.h>

using namespace std;

mutex m1;

int main()
{
    HANDLE hDir[20];
    vector <string> directory_list;
    string f_path;
    string temp1;
    ifstream pfile;

    pfile.open("C:\\Users\\sathish-pt1608\\Desktop\\path_file.txt");

    if (!pfile.is_open())
        cout << "Unable to open the Requested File...";

    while(pfile.good())
    {
        getline(pfile,f_path);
        struct stat path_stat;
        stat(f_path.c_str(),&path_stat);

        if (S_ISREG(path_stat.st_mode))
        {
            int a = f_path.find_last_of('\\');
            directory_list.push_back(f_path.substr(0, a - 1));
        }
        else if(S_ISDIR(path_stat.st_mode))
        {
            DIR *dir;
            struct dirent *ent;

            dir = opendir(f_path.c_str());

            if (dir != NULL)
            {
                directory_list.push_back(f_path);
                while ( (ent = readdir(dir)) != NULL)
                {
                    temp1 = ent->d_name;
                }
                closedir(dir);
            }
            else
            {
                perror("Please Check the Directory Path...");
                EXIT_FAILURE;
            }
        }
    }

    for (int i = 0; i < directory_list.size();)
    {
        LPCTSTR DirName = directory_list[i].c_str();

        hDir[i] = CreateFile(DirName, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);

        FILE_NOTIFY_INFORMATION Buffer[1024];
        DWORD BytesReturned;

        if (!ReadDirectoryChangesW(hDir[i], &Buffer, sizeof(Buffer), TRUE, FILE_NOTIFY_CHANGE_LAST_WRITE,  &BytesReturned, NULL, NULL))
        {
            cout << DirName << endl;
        }
        else
            cout << "THE DIRECTORY HAS BEEN MODIFIED..." << endl;

        if (i == directory_list.size() - 1)
            i = 0;
        else
            i++;
    }
}

2 个答案:

答案 0 :(得分:1)

您可以使用名为日志的Windows功能来检测驱动器上已删除/已更改/创建的文件/文件夹。您需要使用CreateFile()打开驱动器,然后使用DeviceIoControl()不时读取更改的缓冲区。您将获得文件详细信息,如大小,名称,属性等。文件被视为记录,记录大小是使用DeviceIoControl()和bytecount返回的缓冲区获得的。

创建Windows中的日记帐以便以快速/简单的方式查找卷中的更改,因为可能会不时发生多个更改。您可以使用参数FSCTL_QUERY_USN_JOURNAL创建日记和FSCTL_ENUM_USN_DATA以查找所需的记录。

要了解有关期刊的更多信息,请参阅msdn link https://msdn.microsoft.com/en-us/library/windows/desktop/aa363798(v=vs.85).aspx

虚拟源代码,

    ///C drive
    HANDLE drive;
    drive = CreateFile(L"\\\\?\\c:", GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_FLAG_NO_BUFFERING, NULL);
    if (INVALID_HANDLE_VALUE == drive)
    {
        printf("CreateFile: %u\n", GetLastError());
        return 0;
    }

    if (!DeviceIoControl(drive, FSCTL_QUERY_USN_JOURNAL, NULL, 0, buffer, BUFFER_SIZE, &bytecount, NULL))
    {
        printf("FSCTL_QUERY_USN_JOURNAL: %u\n", GetLastError());
        return 0;
    }

    USN_JOURNAL_DATA* journal = (USN_JOURNAL_DATA *)buffer;
    MFT_ENUM_DATA mft_enum_data = {0};
    mft_enum_data.StartFileReferenceNumber = 0;
    mft_enum_data.LowUsn = 0;
    mft_enum_data.HighUsn = journal->MaxUsn;

    for(;;)
    {
        if (!DeviceIoControl(drive, FSCTL_ENUM_USN_DATA, &mft_enum_data, sizeof(mft_enum_data), buffer, BUFFER_SIZE, &bytecount, NULL))
        {
            printf("FSCTL_ENUM_USN_DATA: %u\n", GetLastError());
            return 0;
        }

        USN_RECORD* record;
        USN_RECORD* recordend;
        record = (USN_RECORD *)((USN *)buffer + 1);
        recordend = (USN_RECORD *)(((BYTE *)buffer) + bytecount);

        DWORDLONG filecount = 0;
        while (record < recordend)
        {
            filecount++;

            printf("FileAttributes: %x\n", record->FileAttributes);
            printf("FileNameLength: %u\n", (DWORD)record->FileNameLength);
            printf("RecordLength: %u\n", record->RecordLength);

            WCHAR * filename;
            WCHAR * filenameend;
            filename = (WCHAR *)(((BYTE *)record) + record->FileNameOffset);
            filenameend= (WCHAR *)(((BYTE *)record) + record->FileNameOffset + record->FileNameLength);

            printf("FileName: %s\n", filename);

            record = (USN_RECORD *)(((BYTE *)record) + record->RecordLength);
        }

        mft_enum_data.StartFileReferenceNumber = *((DWORDLONG *)buffer);
    }

答案 1 :(得分:0)

您可以但您需要将其作为异步操作执行,既可以使用LPOVERLAPPED参数,也可以使用它和完成例程。正如文档所说,如果你走后一条路线,你需要处于警惕的等待状态。