Working with Direct Access Files in C++

让人想犯罪 __ 提交于 2019-12-01 14:40:03

What I would to for a project like this is write some primitive functions for reading and writing whole records and updating the file header.

I would create POD type structs to store individual records that are to be read from or written to the data files.

For example:

struct header
{
    uint32_t valid; // number of valid records
    char pad[20]; // padding to make this object 24 bytes
};

struct record
{
    char no[4]; // stock number
    char desc[8]; // description
    uint32_t count;
    uint32_t test_part;
    char pad[4];  // padding to make this object 24 bytes
};

A function to write the header (which is always at file position 0):

std::iostream& write(std::iostream& ios, const header& h)
{
    ios.clear(); // clear any errors
    ios.seekg(0); // move to beginning of file
    ios.write(reinterpret_cast<const char*>(&h), sizeof(h)); // write the header to file
    return ios; // return the stream (for easy error detection/chaining)
}

Same thing to write a record at a specific position:

std::iostream& write(std::iostream& ios, const record& r, size_t pos)
{
    ios.clear(); // clear any errors
    ios.seekg(sizeof(header) + (sizeof(record) * pos)); // move to record's position
    ios.write(reinterpret_cast<const char*>(&r), sizeof(r)); // write the record to file
    return ios; // return the stream (for easy error detection/chaining)
}

You can then write an initialization function in terms of those primitives:

std::iostream& init(std::iostream& ios, size_t num)
{
    // Update the header to zero records
    header h;
    h.valid = 0;
    write(ios, h);

    // create each record with a -1 (EOF) marker
    record r;
    r.test_part = uint32_t(-1);

    // output 20 copies of that record.
    for(size_t pos = 0; pos < num; ++pos)
        write(ios, r, pos);

    return ios;
}

Then invoke it all on a real file a bit like this:

int main()
{
    assert(sizeof(header) == 24);
    assert(sizeof(record) == 24);

    // binary mode io!
    std::fstream fs("records.dat", std::ios::in|std::ios::out|std::ios::binary);

    if(!init(fs, 20))
    {
        std::cerr << "ERROR: initializing data file:" << std::endl;
        return 1;
    }

    // ...
}

NOTE: This code is hastily written and completely untested and merely presented as an example of how this problem can be approached. Hopefully it will give you some ideas.

ALSO: Writing binary files like this is not very portable between systems or even between different versions of the same compiler on the same platform.

Firstly, you seem to have 5 member variables in your class although there are only 4 data in each item. That's dangerous.

After fixing that, I'd just read the whole file into a vector of those objects. For writing, just use a little loop to hop around the vector according to the next number.

You don't need all those getters and setters. Never mind what Grady Booch says: you are the only programmer and you can trust yourself not to screw up your own data. Even if you couldn't, you could just as easily screw it up with the setters as by directly accessing a public member variable.

Just read and parse the file with cin, scanf or whatever you prefer. If the fields are all fixed width then reading a known number of characters with fread is probably your simplest option. Use atoi to make numbers out of strings.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!