Windows C ++:在远程计算机上写入大文件的最快方法是什么?

时间:2019-01-26 16:49:50

标签: c++ performance winapi smb

在我们的应用程序中,我们必须经常在远程计算机上(在同一LAN段中)写入大文件(100 MB到某些GB)。这是我们应用程序的瓶颈。远程计算机可能是本机Windows,也可能是使用SMB的Linux计算机。

我们发现,使用Windows API函数CopyFile首先在本地创建文件,然后将其复制比使用CreateFile直接将UNC路径(或驱动器号)定位到远程计算机要快得多。但是,我们仍然必须进行两次写操作,这似乎远非最佳。

受此问题的第一条评论的启发,我实现了herehere所讨论的CreateFile的FILE_FLAG_OVERLAPPED用法:

  HANDLE hToken;
    auto openResult = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
    if (!openResult)
    {
        gConsoleAndLog << "OpenProcessToken failed with err " << GetLastError() << std::endl;
    }

    TOKEN_PRIVILEGES tp;
    tp.PrivilegeCount = 3;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    tp.Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
    tp.Privileges[2].Attributes = SE_PRIVILEGE_ENABLED;
    if(! LookupPrivilegeValue(NULL, SE_MANAGE_VOLUME_NAME, &tp.Privileges[0].Luid))
        gConsoleAndLog << "LookupPrivilegeValue SE_MANAGE_VOLUME_NAME failed with err " << GetLastError() << std::endl;

    if (! LookupPrivilegeValue(NULL, SE_INCREASE_QUOTA_NAME, &tp.Privileges[1].Luid))
        gConsoleAndLog << "LookupPrivilegeValue SE_INCREASE_QUOTA_NAME failed with err " << GetLastError() << std::endl;

    if (! LookupPrivilegeValue(NULL, SE_ASSIGNPRIMARYTOKEN_NAME, &tp.Privileges[2].Luid))
        gConsoleAndLog << "LookupPrivilegeValue SE_ASSIGNPRIMARYTOKEN_NAME failed with err " << GetLastError() << std::endl;

    auto adjustResult = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
    if (!adjustResult || GetLastError() != ERROR_SUCCESS)
    {
        gConsoleAndLog << "AdjustTokenPrivileges failed with err " << GetLastError() << std::endl;
    }
    else gConsoleAndLog << "AdjustTokenPrivileges SUCCESS" << std::endl;

与第二篇文章不同,即使以管理员身份开始,我也无法设置特权“ SE_ASSIGNPRIMARYTOKEN_NAME”。我不知道这有什么区别。

使用FILE_FLAG_NO_BUFFERING打开文件后| FILE_FLAG_OVERLAPPED,计算的大小已预先分配:

   auto setFileErr = SetFilePointerEx(hFile, endPosition, NULL, FILE_BEGIN);
    if (setFileErr == INVALID_SET_FILE_POINTER)
    {
        CPrintWithOSError(NULL, 0, "SetFilePointerEx FAILED");
        return 1;
    }

    if (!SetEndOfFile(hFile))
    {
        CPrintWithOSError(NULL, 0, "SetEndOfFile FAILED");
        return 1;
    }

    if (!SetFileValidData(hFile, endPosition.QuadPart))
    {
        CPrintWithOSError(NULL, 0, "SetFileValidData FAILED");
        return 1;
    }

这适用于本地驱动器,但是SetFileValidData在远程驱动器上失败。
呼叫失败并显示Windows错误

1314 a required privilege is not held by the client
  • 该如何解决?
  • 还有哪些其他方式可以做到这一点?
  • 有没有 使用WinAPI增加文件缓冲以追加写入的方法?

1 个答案:

答案 0 :(得分:0)

如果您可以访问tifflib源代码,则应该能够通过缓冲要写入输出文件的数据来解决此问题,直到缓冲区已满或文件已关闭。一个简单的FILE *就能做到这一点,使用setvbuf将缓冲区大小设置为1MB左右。