如何修复 CopyFile() 错误 5 - 拒绝访问错误

Posted

技术标签:

【中文标题】如何修复 CopyFile() 错误 5 - 拒绝访问错误【英文标题】:How to fix CopyFile() error 5 - access denied error 【发布时间】:2017-07-14 14:15:32 【问题描述】:

我正在尝试编写一个可以在 Linux 和 Windows 上使用的复制文件功能。它适用于 Linux,但在 Windows 上,尝试使用 WinApi 函数 CopyFile() 时出现错误代码 5。

在文件头文件.h中

这是我应该能够在 Linux 和 Windows 上使用的 File 命名空间中的自定义函数。

class File

public:
    static bool copyFile(std::string source, std::string destination);
private:

在 File.cpp 中

对于 Linux,这很简单:

#ifdef __unix__
  #include "File.h"
  bool File::copyFile(std::string source, std::string destination)
  
      std::string arg = source + " " + destination;
      return launchProcess("cp", arg);
  
#endif

在 Windows 特定的代码块中,我使用 WinAPI (#include ) 函数 CopyFile()。这接受 LPCWSTR 数据类型而不是字符串。为了克服这个问题,我创建了一个将字符串转换为 LPCWSTR 类型的函数。

#ifdef _WIN32    
  #include "File.h"
  #include <Windows.h>
  std::wstring strtowstr(const std::string &str)
  
      // Convert an ASCII string to a Unicode String
      std::wstring wstrTo;
      wchar_t *wszTo = new wchar_t[str.length() + 1];
      wszTo[str.size()] = L'\0';
      MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, wszTo,(int)str.length());
      wstrTo = wszTo;
      delete[] wszTo;
      return wstrTo;
  


  bool File::copyFile(std::string source, std::string destination)
  
      std::wstring wsource = strtowstr(source);
      std::wstring wdestination = strtowstr(destination);

      int result = CopyFileW(wsource.c_str(), wdestination.c_str(), TRUE);

          //for debugging...
          std::wcout << "The error is " << GetLastError() <<std::endl;
          std::wcout  << wsource.c_str() << std::endl;
          std::wcout << wdestination.c_str() << std::endl;              

      if (result == 0)
      
          return false;
      
      return true;
  
#endif

在我的测试程序中

TEST(all,main_copy_file)

    std::cout << "Testing copyFile() function..." << std::endl;

    std::string srcDir = File::currentWorkingDirectory() + "srcDir";
    File::makeDirectory(srcDir);

    std::string destDir = File::currentWorkingDirectory() + "destDir/";
    File::makeDirectory(destDir);

    File::makeFile(srcDir, "testFile", ".txt");

    ASSERT_TRUE(File::fileExists(srcDir + "/testFile.txt")) << "Error: Test file has not been generated" << std::endl;
    ASSERT_TRUE(File::directoryExists(destDir)) << "Error: Destination directory does not exist" <<std::endl;

    ASSERT_TRUE(File::copyFile(srcDir + "/testFile.txt", destDir)) << "Error: Coppy unsucsessfull" << std::endl;
    ASSERT_TRUE(File::fileExists(destDir + "/testFile.txt")) << "Error: CoppyFile() flagged as sucsessfull but file does not exist" << std::endl;


在应用程序中输出(在 Windows 上)

/*
Testing copyFile() function...
The error is 5    
C:\GIT\CorteX\Externals\OSAL\build\Debug/srcDir/testFile.txt
C:\GIT\CorteX\Externals\OSAL\build\Debug/destDir/

error: Value of: File::copyFile(srcDir + "/testFile.txt", destDir)
Actual: false
Expected: true
Error: Coppy unsucsessfull
*/

错误代码 5 是拒绝访问错误。我认为当目录不存在、目录在其他地方打开或我没有权限时会出现此错误。

由于我已经测试过该目录确实存在,所以我认为它必须是后两者之一。我可能只有受限的管理员权限(我不知道),但我可以在没有管理员权限的情况下粘贴到“destDir”中。所以也许它认为目录是打开的?是否存在确保目录关闭的命令?

在Linux上运行时测试成功。

【问题讨论】:

请注意,C++ 已经提供了复制文件的功能。 你能指出其中一个/一些功能的方向吗? 您没有权限。如果其他人以独占访问权限打开文件夹 - 将是另一个错误 - ERROR_SHARING_VIOLATION,如果文件/文件夹不存在 - 又将是另一个错误。如果文件已经存在并且是只读的,也会出现此错误 @Blue7 en.cppreference.com/w/cpp/filesystem/copy @RbMm 你猜我为什么没有权限?我只是想将文件从一个目录复制到另一个目录。这两个文件都在当前工作目录内的目录中,所以我应该没有问题,是吗? 【参考方案1】:

CopyFile API 需要源文件和目标文件的文件名。您的代码传递目标的目录名称。这会导致 API 失败。您还需要附加目的地的文件名。

除此之外,您的代码还有其他几个问题:

Windows 上的路径分隔符是反斜杠 (\)。您正在混合正斜杠 (/) 和反斜杠。根据传递的参数,系统不会将正斜杠转换为反斜杠,然后再将它们传递给较低级别​​的文件 I/O API。 你打电话给GetLastError太晚了。您需要立即调用它,只要它被记录为返回一个有意义的值。不要将它与任何其他代码散布,无论它对您来说多么微不足道。该代码可以修改调用线程的最后一个错误代码并使之无效。 您的代码采用 ASCII 编码字符串。当处理包含非 ASCII 字符的文件时,这将停止工作。这很常见。 new wchar_t[...]std::vector&lt;wchar_t&gt; 给您带来的好处一无所有,除了引入错误的可能性。 您的基于MultiByteToWideChar 的字符串转换实现对不同字符编码的代码单元要求做出了(过度的)假设。这些假设可能不正确。让 API 计算并告诉您目标缓冲区大小,方法是为 cchWideChar 传递 0。 您的字符串转换例程会忽略所有返回值,从而使错误变得非常可能,并且不必要地难以诊断。

【讨论】:

【参考方案2】:

我知道这是一篇旧帖子,但对于在这里遇到需要更多帮助的任何人:

CopyFile 具有以下约束,如果不满足这些约束可能会导致访问被拒绝错误:

    当前用户权限不足 文件正在使用中 文件路径是目录而不是文件 文件是只读的

在我的情况下,上述所有条件都得到了满足,但我仍然遇到同样的错误。帮助我的是一个简单的 SetFileAttributes(filePath,FILE_ATTRIBUTE_NORMAL)

Retrieving and Changing File Attributes

SetFileAttributes

【讨论】:

以上是关于如何修复 CopyFile() 错误 5 - 拒绝访问错误的主要内容,如果未能解决你的问题,请参考以下文章

如何修复错误:无法打开 laravel.log 权限被拒绝?

如何修复错误:mkdir():运行作曲家时权限被拒绝

如何修复访问被拒绝路径错误asp.net应用程序访问网络共享

如何修复以下 Django 错误:“类型:IOError”“值:[Errno 13] 权限被拒绝”

如何在使用 lambda@edge 调整图像大小时修复访问被拒绝错误

如何修复错误无法打开文件,路径 = '/storage/emulated/0/DCIM/Camera/20200818_123041.jpg'(操作系统错误:权限被拒绝,errno = 13)