【问题标题】:How to check if the file is still being copied in cpp using windows API?如何使用 Windows API 检查文件是否仍在 cpp 中复制?
【发布时间】:2012-09-27 07:51:18
【问题描述】:

在我当前的项目中,我们需要检查文件是否仍在复制。

我们已经开发了一个库,它将在特定文件夹以及相应的文件路径上向我们提供诸如 file_added 、 file_removed 、 file_modified 、 file_renamed 之类的操作系统通知。

这里的问题是,假设您添加 1 GB 文件,它会在复制文件时发出多个通知,例如 file_added 、 file_modified 、 file_modified 。

现在我决定通过检查文件是否正在复制来超越这些通知。基于此,我将忽略事件。

我在 C++ 中编写了下面的函数,它告诉文件是否正在被复制,它以文件路径作为输入。 详细信息:-基本上它使用Windows API“CreateFile”来获取文件句柄。如果我们无法获取句柄,则确定为正在复制文件。

问题:- 对于一些较大的文件,例如 2 GB 的 .rar 和 .exe 格式,这不起作用。你能告诉我这是正确的方法吗?如果不欣赏其他方法。

bool isFileBeingCopied(const boost::filesystem::path &filePath)
{
     //Log(INFO, "Checking if the given file is being copied or not for the file [%s]",filePath.string().c_str());
     HANDLE hFile = ::CreateFile(filePath.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
     DWORD dwLastError = GetLastError();

     if(hFile == NULL && hFile == INVALID_HANDLE_VALUE)
     {
          Log(INFO, "Gained invalid handle on the file - hence determining it, as being copied file [%s]",filePath.string().c_str());
          return true;
     }
     else
     {
          if(dwLastError == ERROR_SUCCESS )
          {
                CloseHandle(hFile);
                Log(INFO, "Able to gain the handle on the file - hence determining it, as copied file [%s]",filePath.string().c_str());
                return false;
          }
          else
          {
              Log(INFO, "Not able to gain the handle for the file - hence determining it, as being copied file [%s]",filePath.string().c_str());
              return true;
          }
     }               
}

【问题讨论】:

    标签: c++ file winapi


    【解决方案1】:

    除非您自己复制文件,否则无法从外部确定文件的复制状态。您可能必须使用计时器来检测文件修改事件何时停止发送给您。

    【讨论】:

    • 我认为这样我无法区分是用户手动编辑还是文件复制
    • 看看创建copy hook handler 是否能满足您的需求。
    【解决方案2】:

    使用boost filesystem libs,我们可以确定文件是否被复制。基本上 boost::filesystem::fstream 类为 I/O 操作打开文件。当前正在复制文件时,boost lib 无法打开文件并且 is_open() 方法将返回 false。因此,在这种情况下,我们可以安全地假设文件当前正在被复制。如果文件也损坏或损坏,我们最终会遇到这种情况。

    在所有其他情况下,is_open() 返回 true,我们可以认为文件复制已完成(在此用例中) 希望这段代码有所帮助。

    boost::filesystem::fstream fileStream(filePath, std::ios_base::in | std::ios_base::binary);
    
    if(fileStream.is_open())
    {
        //We could open the file, so file is good
        //So, file is not getting copied.
    }
    else
    {
        //Wait, the file is currently getting copied. 
    }
    

    编辑:添加更多解释

    【讨论】:

      【解决方案3】:

      如果文件之前以dwShareMode = 0,IOW,以独占访问模式打开(并且仍然是),则在关闭之前您将无法再次打开它,无论文件是否是是否被复制(=写入),因此不能依赖函数的返回值 true

      请注意,如果CreateFile() 成功,则调用CloseHandle() 并返回false。在此之后,文件可以立即打开以供另一个进程写入,并且由于可能存在这种竞争条件,因此不能依赖 false 的返回值。如果你想阻止它,在你不再有兴趣拥有对文件的独占访问权之前,你不能关闭句柄。

      因此,这显然不是准确确定文件是否被复制(=写入)的正确方法。而且这似乎是一件毫无意义的事情。

      在我看来,您在这里试图解决错误的问题。您决定检查文件是否被复制(=写入)的真正问题是什么?如果您告诉我们,我们也许可以帮助解决这个真正的问题。

      【讨论】:

      • 不只是独占访问会导致CreateFile() 失败。只要文件没有打开读取共享,因为这段代码要求它,那么它就会失败。
      • @RemyLebeau 对,以前用FILE_SHARE_WRITE 打开的文件将导致CreateFile()isFileBeingCopied() 中失败。
      • 更准确地说,文件不是用FILE_SHARE_READ打开的。
      • 感谢您的宝贵时间。这是上下文。一旦我确定该文件被复制,它将被上传到服务器。想想保管箱服务。我关闭句柄的原因是让用户可以根据需要编辑文件
      • 更多上下文,如果我在操作系统通知后开始上传文件,我最终会上传多个版本的大小不正确的单个文件,因为它仍在被复制。
      猜你喜欢
      • 2019-01-05
      • 2018-09-27
      • 2011-10-17
      • 2017-04-29
      • 2013-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-20
      相关资源
      最近更新 更多