【问题标题】:(C++) How do i read info from a binary file .dat to be stored in an array of struct?(C++) 如何从二进制文件 .dat 中读取信息以存储在结构数组中?
【发布时间】:2018-01-18 03:41:04
【问题描述】:
  • 我不允许使用向量,因为我的教学大纲中没有教授它

我正在做一项关于学生作业分数的读/写/存储的作业。

我在下面使用 2 个结构

struct assessTask
{
    char title [MAX];
    int weight;
    int markUpon;
    float mark;
};

struct subject
{
    char code [MAX];
    char title [MAX];
    int numTask;
    assessTask task [MAX];
    int finalMark;
    UNIGrade grade;
};

我的 write 函数的简短片段:(请告诉我这种风格是否正确/错误)

// run if code is unique        
        strcpy(s[size].code, testcode);
        afile.write (reinterpret_cast <const char *>(&s[size].code), sizeof (s));   

        cin.clear();
        cin.ignore(MAX, '\n');

        cout << "Subject Name: ";
        cin.getline(s[size].title, MAX);
        afile.write (reinterpret_cast <const char *>(&s[size].title), sizeof (s));  

        cout << "No of assessment tasks: ";
        cin >> s[size].numTask;  
        afile.write (reinterpret_cast <const char *>(&s[size].numTask), sizeof (s));

Snippet of whats inside my binary file .dat

所以,在我退出程序后,.dat 将被存储以备将来使用。 每次我打开程序时,它都会检查.dat文件,我可以用它来通过程序查询或更新

void checkBinary(fstream& afile, const char fileName [], subject s[])
{
    afile.open(fileName, ios::in | ios::binary);

    int g = 0;

    while (afile.read (reinterpret_cast <char *>(&s), sizeof (s)))
    {           
        g++;
    }

    cout << g << endl;

    if (g < 1)
    {
        createBinary (afile, "subject.dat", s); 
    } 
    else
    {
        readBinary (afile, "subject.dat", s);
    }

    afile.close();
}

void createBinary (fstream& afile, const char fileName [], subject s[])
{
    afile.open (fileName, ios::out | ios::binary);

    cout << "Begin the creation of binary file " << fileName << endl;

    afile.write (reinterpret_cast <const char *>(&s), sizeof (s));

    afile.close ();

    cout << "Binary file " << fileName
         << " successfully created"
         << endl;   
}

void readBinary (fstream& afile, const char fileName [], subject s[])
{
    afile.open (fileName, ios::in | ios::binary);

    afile.clear();

    afile.seekg(0, ios::end);
    int size = afile.tellg();
    int noOfRecords = size / sizeof (s);
    afile.seekg(0, ios::beg);   


    while (afile.tellg() < noOfRecords)
    {
        afile.read (reinterpret_cast <char *>(&s), sizeof (s));
        /*
        afile.read (reinterpret_cast <char *>(&s[start].code), sizeof (s));
        afile.read (reinterpret_cast <char *>(&s[start].title), sizeof (s));
        afile.read (reinterpret_cast <char *>(&s[start].numTask), sizeof (s));

        for (int i = 0; i < s[start].numTask; i++)
        {
            afile.read (reinterpret_cast <char *>(&s[start].task[i].title), sizeof (s));
            afile.read (reinterpret_cast <char *>(&s[start].task[i].weight), sizeof (s));
            afile.read (reinterpret_cast <char *>(&s[start].task[i].markUpon), sizeof (s));
        }
        */
    }

    afile.close();
}

出于某种原因,我必须在 readbinary() 中使用 afile.clear(),否则返回给我的字节为 -1。

我现在遇到的问题是我需要从 .dat 文件中复制信息并将其存储在某个位置,以便在程序的连续使用期间,我仍然能够检索数据并在 s[] 时显示它.code 已输入。

注意事项:

  • 我正在附加到 .dat,而不是覆盖
  • 我有一个查询功能,可以在用户输入主题代码时读回数据
  • 我尝试在 readbinary() 中使用 cout 来查看它是否读取任何内容。它只是给了我一个空行
  • 我听说我需要将读取的信息存储回数组结构中,但我不知道如何

仍然是 C++ 的业余爱好者,如果我不了解某些上下文,请提前道歉

感谢任何帮助。谢了!

【问题讨论】:

  • 对我来说毫无意义的一件事是文件名和fstream 的传递。如果你应该创建一个文件,主题来自哪里? aFile 是否可能是您的源数据来自哪里,而 `fileName 是您需要读取或写入数据的位置?这种 API 设计没有多大意义:-/
  • 我使用文件将数据读/写到文件名中,即我的 subject.dat

标签: c++ arrays data-structures struct binary


【解决方案1】:

一些事情:

  1. 您需要afile.clear() 的原因是,当您从流中读取数据时,您正在推进它正在读取的文件中的哪个位置。您要做的第一件事就是阅读整个文件......所以任何进一步的阅读当然不会返回任何数据,因为您已完成阅读文件。直到你用clear()重置读取位置

  2. 这条线有问题:

    while (afile.read (reinterpret_cast <char *>(&s), sizeof (s)))
    

sizeof(s) 将等于 sizeof(subject*) 并且您正在读取垃圾内存(我认为);这导致了问题 #3

  1. 不建议这样写:

    void checkBinary(fstream& afile, const char fileName [], subject s[])
    

因为您正在丢失数组的大小!在 C 和 C++ 中,函数参数不是数组(即使它们看起来像),它们是指向第一个元素的指针!当你传递一个数组时,它会“衰减”为一个指针。

为了清楚起见,请注意上面的行完全等于以下内容:

void checkBinary(fstream& afile, const char *fileName, subject *s)

最好这样写你的函数:

std::vector<subject> checkBinary(const std::string &fileName);

注意:文件名作为 std::stringconst 引用 传递以避免不必要的复制。如果char 数组是在堆上分配的,则无需担心手动管理其详细信息及其生命周期。

此外,subject 对象的 vector 被返回,因为此函数通过从文件中读取主题来生成主题。 vector 知道它的大小,因此您无需为sizeof 之类的事情烦恼

所以我可能会像这样实现你的功能之一:

std::vector<subject> checkBinary(const std::string &fileName) {

    // why pass the ifstream if you just open/close it in this function
    // do it locally!
    std::ifstream afile(fileName, ios::in | ios::binary);

    subject s;
    std::vector<subject> subjects;

    // read each subject and then add them to the result array!
    while (afile.read (reinterpret_cast <char *>(&s), sizeof (s))) {           
        subjects.push_back(s);
    }

    cout << subject.size() << endl;

    // these will obviously need to be reworked as well to support the 
    // different methodology
    if (subject.empty()) {
        createBinary ("subject.dat", subjects); 
    } else {
        // do we even NEED a readBinary? we just read them above!
    }

    // NOTE: since we made the ifstream locally, no need to close it
    // explicitly! research the concept of RAII and make your code even simpler
    // :-)
    return subjects;
}

【讨论】:

  • 嘿tks 的帮助! 1. 首先,我不能使用向量,因为它不是我的讲师教的。而且我们的书写格式不包括std::。这似乎是一个方便使用的功能,但遗憾的是,我不允许实现它
  • 2. while (afile.read (reinterpret_cast &lt;char *&gt;(&amp;s), sizeof (s))) sizeof() 不是返回字节以便从头到尾检查吗?
  • 3.只是为了检查,首先写入功能是否正确?恐怕它没有正确存储它
  • 1.好的,如果没有向量,那么你应该传递一个指针和数组的大小。 2. 不,sizeof 返回被传递的东西的 sizeof ... 这是一个指针,因为参数永远不是数组! 3.我不确定你的write函数是否正确,因为它只是一个sn-p。但是您当然可以一次写入整个对象,就像一次读取整个对象一样。
  • 4. void checkBinary(fstream&amp; afile, const char fileName [], subject s[])我的讲师是这样写的,所以我只能效仿
猜你喜欢
  • 2014-05-04
  • 2015-06-27
  • 2011-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-19
  • 2021-12-18
  • 1970-01-01
相关资源
最近更新 更多