c++ - 在 C++ 中使用直接访问文件

标签 c++ file random-access

我对 C++(以及一般的编程)非常陌生,并且正在从事一个让我难过的项目(不难做哈)。该项目涉及直接访问文件。我们要创建一个由一系列零件记录组成的文件。以下是一些规范:

Should contain a header record (24 bytes - filled) indicating the number of valid items.

Each (24 byte-long) data record will contain a stock number (4 digits max), a description (8 characters max), a count (4 digits), and a "test part" indicator( 4 digits max => -1 - end of file).

This file will initially hold 20 blank (dummy) records and will be created sequentially.

Once the file has been created, an update sequential text file will be accessed based on stock numbers and new records will be inserted into the file.

When the update is complete, the valid parts records will be printed in order starting at stock record "1".

Update by reading the text update file (prog4.dat) and seeking the file position based on the stock number (don't forget the header record)

例如:

Initial (empty)
Input (updates)
    1 widgits 25 3
    6 gidgits 12 8
    8 kidgits 6 -1
    3 didgits 11 6
Output
    1 widgits 25
    3 didgits 11
    6 gidgits 12
    8 kidgits 6

我对直接访问文件一无所知,所以一直在查看我在 Google 上找到的几个不同的链接(特别是 http://cee-ux49.cee.illinois.edu/cee490/public_html/pdfs_vgs/aL23_Direct_Access_Files.pdfhttp://www.learncpp.com/cpp-tutorial/137-random-file-io/),但我无法弄清楚如何制作它为这个特定的程序工作。

我没有在代码方面做太多事情,因为就像我说的,这让我很困惑,我所做的主要基于第一个链接,所以我不知道它是否正确(不确定是什么size 给 vector ,因为我不完全确定我的具体问题会是什么(也许是零件数组?)),但这是我能想到的一点点。

#include <iostream>
#include <string>
#include <fstream>
#include <stream>
using namespace std;

class records {
public:
        int getStckNumber() {
                return stockNumber;
        }
        void setStockNumber(int stockNum) {
                stockNumber = stockNum;
        }

        string getItemDespcription() {
                return itemDescription;
        }
        void setItemDespcription(string itemDescrip) {
                itemDescription = itemDescrip;
        }

        int getItemAmount() {
                return itemAmount;
        }
        void setItemAmount(int itemAmt) {
                 itemAmount = itemAmt;
        }

        int getNext() {
                return next;
        }
        void setNext(int nxt) {
                next = nxt;
        }
private:
        int stockNumber;
        string itemDescription;
        int itemAmount;
        int next;
        int recNum;
}


int main() {
        int stockNumber;
        string itemDescription;
        int itemAmount;
        int next;
        int recNum;
        int recSize = sizeof(int) + sizeof(string) + sizeof(int) + sizeof(int) + sizeof(int);

        istream updateFile;
        updateFile.open("prog4.dat");
        if(!updateFile) {
                cerr << "Open Failure" << endl;
                exit(1);
        }
}

这是我将用于更新的文件:

10 zidgits 17 -1
14 lidgits 2 7
6 gidgits 12 8
1 bidgits 25 3
16 widgits 9 10
7 midgits 0 2
3 didgits 11 6
5 tidgits 5 16
2 pidgits 7 5
8 kidgits 6 14

以下是我的一些具体问题:

  1. 我将如何将来自 updateFile 的信息存储到要写入输出文件(尚未创建)的变量中?

  2. 我如何让它以正确的顺序写入数据,因为它基于 updateFile 中每行的最后一个数字。

例如,输出文件应该从最低的 stockNumber 开始,即 1,因此根据该文件,stockNumber 为 1 的项目是 bidgits。然后该文件应该查看该行 (3) 的最后一个数字,并使用该库存号 (didgits) 写入该项目的信息,依此类推。

这些是我现在突然想到的主要问题,但我相信随着这个过程的进行会有更多的问题出现。任何帮助将不胜感激。此外,这将在大约 5 小时内到期,所以我会尽可能地坚持我已经拥有的代码(我知道当然会添加更多代码)如果可能的话。

最佳答案

我想为这样的项目编写一些原始函数来读取和写入整个记录并更新文件头。

我会创建 POD 类型结构来存储要从数据文件读取或写入数据文件的单个记录。

例如:

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
};

写入 header 的函数(始终位于文件位置 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)
}

在特定位置写入记录也是一样:

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)
}

然后您可以根据这些原语编写初始化函数:

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;
}

然后像这样在真实文件上调用它:

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;
    }

    // ...
}

注意:此代码是仓促编写的,完全未经测试,仅作为解决此问题的示例提供。希望它能给你一些想法。

另外:像这样编写二进制文件在系统之间甚至在同一平台上同一编译器的不同版本之间都不是很可移植。

关于c++ - 在 C++ 中使用直接访问文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26401176/

相关文章:

java - 使用最快且高效的字符串搜索方法随机搜索文本文件中的关键字

c++ - 我如何从包含很多行的文件 .dat 中读取并在 EOF 之前只收集数组中的几个值?

c++ - 创建 "no-op"版本的 dll?

c++ - 调用和传递 DLL 变量 C++

c - 读取 XML 文件并使用 C 打印标签

java - 在Java中替换所有文件类型中的字符串

java - AbstractList.java中RandomAccess的操作

c++ - Sqlite undefined reference to `sqlite3_open' error in Netbeans C++ on Ubuntu, Integrating SQLite into Netbeans C++ Ubuntu

scala - Spark : How to get the latest file from s3 in the last 10 days

java - DeleteByName 方法未从 randomAccessFile 中删除