繁体   English   中英

错误地读取或写入二进制文件

[英]Reading or writing binary file incorrectly

代码的输出显示了Student结构的所有变量的乱码。 运行显示功能时。

我在二进制文件的每个添加和显示功能中都包含了相关代码。

对于第二个功能,每次for循环运行时, seekg指针是否会自动移动以读取下一条记录?

//Student struct
struct Student
{
    char name [30];
    float labTest;
    float assignments;
    float exam;
};

//Writing function   
afile.open(fileName,ios::out|ios::binary);

Student S;
strcpy(S.name,"test");
S.labTest = rand()%100+1;
S.assignments = rand()%100+1;
S.exam = rand()%100+1;

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

afile.close();



//Reading function
afile.open(fileName,ios::in|ios::binary);

afile.seekg(0,ios::end);

int nobyte = afile.tellg();
int recno = nobyte / sizeof(Student);

Student S;

//Loop and read every record
for(int i = 0;i<recno;i++)
    {
        afile.read(reinterpret_cast<char*>(&S),sizeof(S));
        cout << "Name of Student: " << S.name << endl
        << "Lab mark: " << S.labTest << endl
        << "Assignment mark: " << S.assignments << endl
        << "Exam mark: " << S.exam << endl << endl;
    }

afile.close();

您的代码有很多问题:

调用write函数将永久覆盖最后写入的数据集。 您必须添加: ios::append ,以便新数据将被写入您之前写入的最后一个数据之后。

使用afile.seekg(0,ios::end);移动之后 要获取tellg文件的大小,必须先返回文件的开头,然后再读取afile.seekg(0,ios::beg)

看起来您使用了char数组来存储字符串。 这不是c ++样式! 使用它很危险。 如果使用strcpy,则可以复制一个字符串,该字符串的长度大于为其保留的空间。 因此,您应该更喜欢std::string 但是您不能简单地编写一个将std::string为二进制的结构! 要获取检查副本,您可以使用strncpy ,但这仍然不是c ++;)

对于第二个功能,每次for循环运行时,seekg指针是否会自动移动以读取下一条记录?

是的,文件位置会移动,每次成功读取和写入。

通过简单地转储内存内容来写二进制数据的一般说明:这不是一个好主意,因为如果使用相同的机器类型和相同的编译器选项,则只能读回该数据。 这意味着:具有不同字节序的计算机将读取完全损坏的数据。 另外,不同的整数类型(32位和64位)也会破坏该代码!

因此,您应该花一些时间如何以移植的方式序列化数据。 有许多库可用于读取/写入复杂数据类型,例如std :: string或容器类型。

使用SO的提示:请提供每个人都可以简单地剪切,粘贴和编译的代码。 我不知道您的Student结构是什么。 所以我有很多假设! 您的结构是否真的使用char []? 我们不知道!

#include <iostream>
#include <fstream>
#include <cstring>

const char* fileName="x.bin";

struct Student
{
    char name[100]; // not c++ style!
    int labTest;
    int assignments;
    int exam;
};

// Writing function   
void Write()
{
    std::ofstream afile;
    afile.open(fileName,std::ios::out|std::ios::binary|std::ios::app);

    Student S;
    strcpy(S.name,"test"); // should not be done this way! 
    S.labTest = rand()%100+1;
    S.assignments = rand()%100+1;
    S.exam = rand()%100+1;

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

    afile.close();
}

void Read()
{
    //Reading function
    std::ifstream afile;
    afile.open(fileName,std::ios::in|std::ios::binary);

    afile.seekg(0,std::ios::end);

    int nobyte = afile.tellg();
    int recno = nobyte / sizeof(Student);

    afile.seekg(0, std::ios::beg);

    Student S;

    //Loop and read every record
    for(int i = 0;i<recno;i++)
    {
        afile.read(reinterpret_cast<char*>(&S),sizeof(S));
        std::cout << "Name of Student: " << S.name << std::endl
            << "Lab mark: " << S.labTest << std::endl
            << "Assignment mark: " << S.assignments << std::endl
            << "Exam mark: " << S.exam << std::endl << std::endl;
    }

    afile.close();
}

int main()
{
    for ( int ii= 0; ii<10; ii++) Write();
    Read();
}

编辑。 显然,我的回应还为时已晚。 Klaus编写了一个更好,更全面的解决方案,涉及有关C样式char []std::string和平台的字节序的其他问题。

您应该附加到为每个记录打开的文件。 在您的代码中根本没有这个。 请以我们可以复制,粘贴和测试的方式编写代码。 作为一个工作示例,您应该编写一些可以按以下方式编译和运行的代码:

#include <algorithm>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

// Student struct
struct Student {
  char name[30];
  float labTest;
  float assignments;
  float exam;
};

// Serializer
void serialize_student(const Student &s, const std::string &filename) {
  // Append to the file, do not overwrite it
  std::ofstream outfile(filename, std::ios::binary | std::ios::app);
  if (outfile)
    outfile.write(reinterpret_cast<const char *>(&s), sizeof(Student));
}

// Deserializer
std::vector<Student> deserialize_students(const std::string &filename) {
  std::ifstream infile(filename, std::ios::binary);
  std::vector<Student> students;
  Student s;
  while (infile.read(reinterpret_cast<char *>(&s), sizeof(Student)))
    students.push_back(std::move(s));
  return std::move(students);
}

int main(int argc, char *argv[]) {
  // Generate records
  std::vector<Student> mystudents;
  std::generate_n(std::back_inserter(mystudents), 10, []() {
    Student s;
    std::strcpy(s.name, "test");
    s.labTest = rand() % 100 + 1;
    s.assignments = rand() % 100 + 1;
    s.exam = rand() % 100 + 1;
    return s;
  });

  // Print and write the records
  for (const auto &student : mystudents) {
    std::cout << student.name << ": [" << student.labTest << ','
              << student.assignments << ',' << student.exam << "].\n";

    serialize_student(student, "students.bin");
  }

  // Read and print the records
  auto records = deserialize_students("students.bin");
  std::cout << "===\n";
  for (const auto &student : records)
    std::cout << student.name << ": [" << student.labTest << ','
              << student.assignments << ',' << student.exam << "].\n";

  return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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