简体   繁体   中英

Do I understand the combination of fseek and fwrite/fread correctly

So I have been asked to "translate" some code from C to C++, what the request really is, is to remove raw C as much as possible and replace it with C++ STL function calls.

One of the things I have to change is the usage of pwrite and pread to std::fwrite and std::fread respectively. However, the current code utilize heavily the offset option of pwrite and pread Because data is being written to a device on a Linux or BSD system, ie, /dev/sda1 .

But std::fwrite and std::fread does not have the offset parameter like pwrite and pread . So from what I gather I would need to seek to the offset in the file first using std::fseek and then do the write/read operation. Is my understanding of this correct?

I have written a small test program to validate my assumptions, see below, but I would like to be a little more sure before just firing of the code.

The test program is compiled like this: clang++ -std=c++17 main.cpp

#include <vector>
#include <string>

#include <ctime>
#include <algorithm>

#include <cstdio>

void write(const std::string& device, const size_t offset, const std::vector<uint8_t>& data)
{

    std::FILE* fp = std::fopen(device.c_str(), "wb");

    if (offset != 0)
    {
        std::fseek(fp, 0, offset);
    }
    
    std::fwrite(data.data(), sizeof(uint8_t), data.size(), fp);
    std::fclose(fp);
}

std::vector<uint8_t> read(const std::string& device, size_t offset, const size_t size)
{
    std::vector<uint8_t> data(size);

    std::FILE* fp = std::fopen(device.c_str(), "rb");

    if (offset != 0)
    {
        std::fseek(fp, 0, offset);
    }

    std::fread(data.data(), sizeof(uint8_t), size, fp);

    std::fclose(fp);
    return data;
}


std::vector<std::vector<uint8_t>> generate(const size_t num_vec, const size_t data_size)
{
    std::vector<std::vector<uint8_t>> vectors;

    for (size_t i = 0; i < num_vec; ++i)
    {
        std::vector<uint8_t> data(data_size);
        std::generate(data.begin(), data.end(), rand);
        vectors.push_back(data);
    }
    return vectors;
}

int main(void)
{
    srand(static_cast<uint32_t>(time(0)));
    
    const std::string device = "/dev/sda1";
    const size_t size = 4096;
    const size_t num_vec = 4;

    auto vectors = generate(num_vec, size);

    size_t offset = 0;
    
    for (const auto& vec : vectors)
    {
        write(device, offset, vec);
        auto other = read(device, offset, size);

        if (vec != other)
        {
            std::puts("success");
        }
        else
        {
            std::puts("failure");
        }

        offset = offset + size;
    }    
}

You swapped some parameters. Your fseek call should look like this

    if (offset != 0)
    {
        std::fseek(fp, offset, SEEK_SET);
    }

Otherwise your understanding is correct. You seek, then you read. Note that this two-step solution is a) slower (two system calls) and b) not threadsafe if you use the same FILE* in multiple threads.

Since you mentioned translating to C++: fwrite and fseek are parts of the C library. If you want an STL C++ solution, switch to std::fstream instead.

#include <fstream>

void write(const std::string& device, const size_t offset,
           const std::vector<uint8_t>& data)
{

    std::ofstream fp {device, std::ios::binary };
    if (offset != 0)
    {
        fp.seekg(offset);
    }
    
    fp.write(reinterpret_cast<const char*>(data.data()),
            sizeof(uint8_t) * data.size());
}

Your understanding is correct, but the parameters are wrong. To seek a n th byte from beginning of a file use:

// parameter descriptions:
//  descriptor, offset, origin
std::fseek(file, n, SEEK_SET);

From description of the function:

If the stream is open in binary mode, the new position is exactly offset bytes measured from the beginning of the file if origin is SEEK_SET, from the current file position if origin is SEEK_CUR, and from the end of the file if origin is SEEK_END. Binary streams are not required to support SEEK_END, in particular if additional null bytes are output.

See example at the bottom of a cppreference page .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM