从文件 returns 读取一个我没想到的结果,试图理解为什么

Reading from file returns a result I didn't expect, trying to understand why

我有这段代码,其中包含一个 class 和一个主要函数:

class Employee {
    int m_id;
    string m_name;
    int m_age; public:
    Employee(int id, string name, int age) :m_id(id), m_name(name), m_age(age) {}
    friend ostream& operator<<(ostream& os, const Employee& emp)
    {
        os << emp.m_id << " " << emp.m_name << " " << emp.m_age
           << endl;     
        return os;
    }
};

int main() {
    const int Emp_Num = 3;
    fstream fs("dataBase.txt", ios::out);
    if (!fs) {
        cerr << "Failed opening file. Aborting.\n";
        return -1;
    }

    Employee* list[Emp_Num] = 
        { new Employee(1234, "Avi", 34),
          new Employee(11111, "Beni", 24),
          new Employee(5621, "Reut", 26) };
    for (int i = 0; i < Emp_Num; i++) 
    {
        fs << (*list[i]);
        delete list[i];
    }
    fs.close();

    fs.open("dataBase.txt");
    if (!fs) {
        cerr << "Failed opening file. Aborting.\n";
        return -1;
    }
    fs.seekg(4);
    string strRead;
    fs >> strRead;
    cout << strRead << endl;
    fs.seekg(6, ios::cur);
    fs >> strRead;
    cout << strRead << endl;
    fs.seekg(-9, ios::end);
    fs >> strRead;
    cout << strRead << endl;
}

这是我的理解,第一个文件打开和关闭后,文件 dataBase.txt 应该是这样的:

1234 Avi 34

11111 Beni 24

5621 Reut 26

我的问题是读取和输出到控制台。 我打开文件后,我当前位置的指针在第一个字节,也就是1234之前的1

我从文件开头找4, 所以我的指针应该在 1234Avi 之间的 space 之前(之前)。

现在我将下一个字符串放入我的字符串变量 strRead, 现在 strRead 包含“Avi”,指针应该在 Avii 和它后面的 space 之间。

现在我从我现在的位置求6, 据我统计,这些是我通过的 6 个字节:

  1. Space

  2. 3

  3. 4

  4. Line break (return)

  5. 1

  6. 1

所以我的指针应该在第二行,在前两行之后。

我的意思是这样的:

11|111 Beni 24

现在我得到一个 strRead 的字符串,根据我对代码 strRead 的理解,现在应该包含“111”,而不是,出于某种原因,它包含并稍后输出“1111”。

有人可以解释一下为什么会这样吗? 第一行drop和第二行第一个字母之间没有字符,所以应该只算1个字节...

我做了以下测试:

我有 运行 你的代码的第二部分(从文件中读取)在一个文件中,文本为:

1234 Avi 34 11111 Beni 24 5621 Reut 26

所以,我用 spaces 替换了 行尾 ,代码打印到控制台输出了预期的结果 111。然后我开始怀疑 seek 跳过行尾。

然后我更改了代码(不修改文件)并以二进制模式处理文件:

//...
fstream fs("dataBase.txt", ios::out | ios::binary);
//...
fs.open("dataBase.txt",  ios::in | ios::binary );
//...

再次得到预期的结果:111

两种情况有什么变化?

好吧,在纯文本(不是二进制模式)中,行尾实际上是 2 个字符(这可能因其他平台而异,我在 Windows 上复制它):\r\n。这就是为什么您正在阅读四个 (1111) 而不是三个 (111).

Avi 之后的 space 算起 6 个位置:

  A v i _ 3 4 \r \n 1 1 1 1 1
                    ^
        1 2 3  4  5 6 7 8

在我执行的第一个测试中,space(只有一个字符)替换了其中两个。

  A v i _ 3 4 _ 1 1 1 1 1
                  ^
        1 2 3 4 5 6 7 8

并且在二进制模式下,两个字符都表示为一个单独的单元来读取(我没有调查这是否与平台相关)。

A v i _ 3 4 B 1 1 1 1 1
                ^
      1 2 3 4 5 6 7 8

B 在这里代表一些二进制代码。