- 我不允许使用向量,因为它在我的教学大纲中没有教授
我正在做学生作业成绩的读/写/存储作业。
我在下面使用 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;
};
我的写作功能的简短片段:(请告诉我这种风格是否正确/错误)
// 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));
我的二进制文件中的内容片段 .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++的业余爱好者,如果我不了解一些上下文,我提前道歉
任何帮助,不胜感激。 啧啧!
几件事:
-
之所以需要
afile.clear()
,是因为当您从流中读取时,您正在推进文件中正在读取的位置。您要做的第一件事就是阅读整个文件...因此,任何进一步的读取当然都不会返回任何数据,因为您已经完成了文件读取。直到您使用clear()
重置读取位置 -
这条线有问题:
while (afile.read (reinterpret_cast <char *>(&s), sizeof (s)))
sizeof(s)
将等于sizeof(subject*)
,并且您正在读取垃圾内存(我认为);这导致问题#3
-
不建议这样写:
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::string
和常量引用传递,以避免不必要的副本。无需担心手动管理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;
}