C++目录监视-如何检测副本已结束

C++ Directory Watching - How to detect copy has ended

本文关键字:检测 副本 结束 何检测 监视 C++      更新时间:2023-10-16

我有一个文件复制到的文件夹。我想观察它,并在文件复制到目录后立即处理它们。我可以检测文件何时在目录中,无论是通过轮询(我当前的实现)还是在一些测试中使用我在网上找到的一些示例中的Windows API。

问题是,我检测到文件是何时首次创建的,并且它仍在复制中。这使得我的程序,需要访问文件,通过错误(因为文件还不完整)。如何不检测复制何时开始,而是检测复制何时结束?我在Windows上使用C++,所以答案可能取决于平台,但如果可能的话,我更希望它与平台无关。

您可以使用锁定文件或特殊的命名约定。最简单的是后者,其工作原理如下:

假设您想移动一个名为"fileA.txt"的文件,当将其复制到目标目录时,请将其复制至"fileA.txt.partial"或类似的位置。复制完成后,将文件从"fileA.txt.partial"重命名为"fileA.txt"。因此,就观看程序所见,"fileA..txt"的外观是原子的。

前面提到的另一个选项是锁定文件。因此,当你复制一个名为"fileA.txt"的文件时,你首先创建一个名"fileA.txt.lock"的文件。复制完成后,你只需删除锁定文件。当观看程序看到"fileA.txt"时,它应该检查"fileA.txt.lock"是否存在,如果存在,它可以等待或在未来根据需要重新访问该文件。

您不应该进行轮询。使用FindFirstChangeNotification(http://msdn.microsoft.com/en-us/library/windows/desktop/aa364417%28v=vs.85%29.aspx)以监视目录的更改。

然后使用等待功能(http://msdn.microsoft.com/en-us/library/windows/desktop/ms687069%28v=vs.85%29.aspx)等待更改通知发生。

概述和示例如下:http://msdn.microsoft.com/en-us/library/windows/desktop/aa365261%28v=vs.85%29.aspx

我不确定如何准确地确定文件写入完成。Evan Teran的回答是个好主意。

你可以使用这样的东西,这是经过测试和工作的

bool IsFileDownloadComplete(const std::wstring& dir, const std::wstring& fileName) 
{
    std::wstring originalFileName = dir + fileName;
    std::wstring tempFileName = dir + L"temp";
    while(true)
    {
        int ret = rename(convertWstringToString(originalFileName).c_str(), convertWstringToString(tempFileName).c_str());
        if(ret == 0)
            break;      
        Sleep(10);
    }   
    /** File is not open. Rename to original. */
    int ret = rename(convertWstringToString(tempFileName).c_str(), convertWstringToString(originalFileName).c_str());
    if(ret != 0)
        throw std::exception("File rename failed"); 
    return true;
}