fstream::write 和 fstream::read 改变读写指针

fstream::write and fstream::read changing both reading and writing pointers

我正在学习如何在文件上写入记录并读取它。
我创建了一个名为 student 的 class,class 具有 enterStudentshowStudentprintInsideFile(学生信息)等功能,.... ..
当我尝试将学生信息写入文件时,它起作用了。
当我尝试从文件中读取所有学生信息时,它有效
当我尝试同时执行这两项操作时,发生了意想不到的事情(没有显示)

我以为是 file.flush() 的问题,所以当我删除它时,输出的文本是不可读的
我可以关闭文件并再次打开它,但我认为这很愚蠢
代码是:

#include <iostream>
#include <string>
#include <fstream>


using namespace std;

class student {
private:
    char id[5], name[20], age[5], address[50], gender[5];
public:
    void enterStudent() {
        cout << "Enter student id : "; cin >> id;
        cout << "\nEnter student name : "; cin >> name;
        cout << "\nEnter student age : "; cin >> age;
        cout << "\nEnter student address : "; cin >> address;
        cout << "\nEnter student gender : "; cin >> gender;

    }
    void showStudent() {
        cout << "#########student data##########\n";
        cout << "student id : "<< id;
        cout << "\nstudent name : " << name;
        cout << "\nstudent age : " << age;
        cout << "\nstudent address : " << address;
        cout << "\nstudent gender : " << gender<<endl;
    }
    void printInsideFile(fstream &file) {
        file.write(id,sizeof(id));
        file.write(name, sizeof(name));
        file.write(age, sizeof(age));
        file.write(address, sizeof(address));
        file.write(gender, sizeof(gender));
        file.flush();
    }
    bool readFromFile(fstream &file) {
        if (file.eof())
            return 0;
        file.read(id, sizeof(id));
        file.read(name, sizeof(name));
        file.read(age, sizeof(age));
        file.read(address, sizeof(address));
        file.read(gender, sizeof(gender));
        if (file.eof())
            return 0;
        return 1;
    }
    void showAllFromFile(fstream &file) {
        while (this->readFromFile(file)) 
            this->showStudent();
    }
};

int main() {
    student s;
    fstream file;

    file.open("a.txt", ios::in | ios::out | ios::app);
    if (!file)
        goto k270;
    
    s.enterStudent();
    s.printInsideFile(file);

    //when i read one student , it works okay

    //s.readFromFile(file);
    //s.showStudent();

    //when i try to read multiple students , it doesn't work at all
    s.showAllFromFile(file);




    file.close();


k270:
    system("pause");
    return 0;
}

问题不是 ios::app

似乎函数 file.write()file.read() 改变了读指针和写指针。
即使你同时使用 file<<"text";file>>array of chars;指针正在改变。

我搜索了一下,但没有找到解释,但我找到了 ostream::write and istream::read 的代码,它们是高级的,所以如果有人检查 link 并告诉我们为什么

注意,当读取指针指向文件末尾时,它不会打印任何内容

考虑到我对 std::ios::app 的经验最少,我很想知道它到底是如何工作的。

我做了以下 MCVE on coliru ,(我相信)按照 OP 的预期工作:

#include <fstream>
#include <iostream>

int main()
{
  // open a text file
  std::fstream file("test.txt", std::ios::in | std::ios::out | std::ios::app);
  // remember current position of read head
  file.seekg(0, std::fstream::end); // a trick to update the read head before writing anything
  std::fstream::pos_type pos0 = file.tellg();
  std::cout << "pos0: " << pos0 << '\n';
  // write a line to end of text
  std::cout << "Write a line.\n";
  file << "A line written by main.cpp" << std::endl;
  std::cout << "pos after writing: " << file.tellg() << '\n';
  // rewind to remembered position of read head
  file.seekg(pos0);
  // read the last written line
  { std::string buffer; std::getline(file, buffer);
    std::cout << "Last line: '" << buffer << "'\n";
  }
  // rewind to the beginning of file
  file.seekg(0);
  // read all
  std::cout << "Read all:\n";
  for (std::string buffer; std::getline(file, buffer);) {
    std::cout << "'" << buffer << "'\n";
  }
}

测试环节:

g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp \
  && echo -e "1st line written by echo\n2nd line written by echo\n3rd line written by echo" > test.txt \
  ; ./a.out
pos0: 75
Write a line.
pos after writing: 102
Last line: 'A line written by main.cpp'
Read all:
'1st line written by echo'
'2nd line written by echo'
'3rd line written by echo'
'A line written by main.cpp'

备注:

  1. 我完全确定 file.seekg(0)read all 之前需要将读取的文件头倒回文件开头。

  2. 我不确定 read the last written line
    我发现 file.seekg(pos0); 是必要的。
    很明显,前面的write好像碰到了write head(当然)还有read head。

  3. 我在使用 std::istream::tellg() 检索正确的读取头位置时遇到了一些麻烦。 它在第一个文件输出之后而不是之前返回预期值。
    我的最后一招是 file.seekg(0, std::fstream::end); 在写入任何内容之前将读取头移动到文件末尾。

  4. 对于示例中完全没有任何错误检查,我深表歉意。
    当然,这必须在认真的应用程序中添加。
    我将其保留下来是为了尽可能减少示例代码。
    此外,我没有将错误处理视为 OP 示例代码中的问题。