C ++打开文件并写入文件的任意位置

时间:2016-08-22 13:31:03

标签: c++ windows performance io

我需要打开现有文件并到该文件的任意位置。也位于可能大于文件当前大小的位置。

使用“ab”打开文件会在每次调用写入操作时将位置指示器设置为文件末尾 - 这样就无法工作。

使用“w + b”“wb”打开文件会导致文件被多次写入(复制?)。 Filesize从0开始多次 - 这需要很长时间。观看执行以下测试(1次运行)时会发生什么的视频:http://screencast.com/t/Uj5ymikZUYJ

BOOST_AUTO_TEST_CASE(FileWriteTest_W_PLUS_B) {
    auto started = chrono::high_resolution_clock::now();

    FILE *filePointer = nullptr;
    auto tmpFilename = string("C:\\temp\\") + boost::uuids::to_string(boost::uuids::random_generator()());
    auto bufferSize = 1024 * 1024;

    unique_ptr<unsigned char[]> buffer(new unsigned char[bufferSize]);
    RAND_bytes(buffer.get(), bufferSize);

    for (long long i = 0; i < 5; i++) {
        //Open file
        int openError = fopen_s(&filePointer, tmpFilename.c_str(), "w+b");  
        if (openError != 0)
            BOOST_FAIL(string("Failed to open file ") + tmpFilename);

        auto CurrentPosition = 1024LL * 1024LL * 1024LL * i;

        //Set position to 0/1/2/3/4 GB 
        fsetpos(filePointer, &CurrentPosition);

        //Write 1 GB of data at current position
        for (int n = 0; n < 1024; n++) {
            int written = fwrite(buffer.get(), sizeof(unsigned char), bufferSize, filePointer);
            if (written != bufferSize) {
                BOOST_FAIL(string("Unable to write ") + to_string(bufferSize) + string(" to file ") + tmpFilename + string(" at position ") + to_string(CurrentPosition));
            }
        }

        //Close file
        fclose(filePointer);
    }

    auto ended = chrono::high_resolution_clock::now();
    cout << "Time :" << duration_cast<duration<double>>(ended - started).count() << " seconds";
}

所以我的问题是:有没有办法打开现有文件并写入任意位置(也在大于当前大小的位置) - 没有得到我目前使用的性能损失“wb” / “w + b”

或者我是否必须将文件设为最终大小 - 我第一次写文件? (例如Torrent客户似乎这样做。)

由于I / O性能不佳,fstream不是一种选择。 (见writing-a-binary-file-in-c-very-fast

2 个答案:

答案 0 :(得分:3)

您应该以{{1​​}}模式打开流。 "r+b"模式会导致文件被截断。如果该文件不存在,则必须首先使用"w"创建该文件。

但请注意,"wb"可能无法将当前位置设置为超出文件末尾。如果需要,您应该检查返回值并将文件填充到目标位置。

对于作为字节偏移有意义的位置,流也必须以fsetpos()的二进制模式打开。默认情况下,流更多地以文本打开,在某些系统(如Windows)上可能会阻止正确的偏移管理。

答案 1 :(得分:0)

我建议您手动跟踪文件大小,如果大小太小,请使用以下内容:

fseek(f, 0, SEEK_END);
int pos = ftell(f);

while (pos < wantedsize) {
  fputc(0, f); ++pos;
}

请注意,文件超过~2GB会出现问题。