首页 > 解决方案 > 为什么“换行”会偏移 .txt 文件中的所有字符字节位置 +1?

问题描述

当我使用fstream::tellg时,在读取第一个字符后fstream::get (char),结果是:1

然后我在第一个字符之后插入一个“新行”

fstream::seekg到开头:0

当我使用fstream::tellg时,这次读入第一个字符后,结果是:2

如果我将: "abc", 插入到 .txt 文件中:

但是如果我插入:"abc\n""abc" << endl;

这是什么原因?

我知道“换行符”也是字符。我不明白的是tellg读取字符后结果的偏移量。每次使用“换行符”时,此偏移量都会增加一。

更新

标签: c++filenewlinefstream

解决方案


我的猜测是您正在 Microsoft 操作系统上编写代码。

在文本文件中,Microsoft 操作系统(和相关软件)期望用\r\n序列标记行尾,因此当您将换行符写入(文本)文件时,它会\n\r\n. 因此,即使您只在流中插入了一个字符,也会导致将两个字符写入外部文件。

如果您关心确保外部文件的内容与您插入到流中的内容完全匹配,这可能表明您想要 C++ 标准库将其视为二进制文件的内容,您可以通过指定std::ios::binary何时打开文件。

现在,当您处理文本文件时,tellg确实不会产生一个非常有意义的数字。我们所拥有的是这样的:

在此处输入图像描述

上面是你看到的数据。下侧是存储在文件中的数据。当您调用tellg 时,它会告诉您沿着下侧的位置——即相对于文件开头的位置。但是,根据文件中之前有多少 \r\n 对,这可能会导致上一行中的字符数不同,这就是您从文件中读取数据时会看到的内容。

这意味着tellg的结果只能以几种相当特定的方式使用——大多数情况下,当您从tellg获得一个数字时,您可以将该数字返回给seekg,然后从同一个地方开始阅读。

就您的代码而言,我想我看不出我理解您的问题在说什么。我稍微重写了代码以一起显示结果:

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

using namespace std;

std::string show(char x) {
    if (x > 32)
        return std::string(1, x);
    else switch (x) {
    case '\r': return "<\\r>";
    case '\n': return "<\\n>";
    case '\t': return "<\\t>";
    default: return "<BAD>";
    }
}

void display_txt_file(fstream& file)
{
    file.seekg(0, ios_base::beg);
    char x;
    cout << "tellg: " << file.tellg() << "| ";
    while (file.get(x))
    {
        cout << "'" << show(x) << "' tellg: " << file.tellg() << "| ";
    }
    file.clear();
    file.seekg(0, ios_base::end);
    std::cout << "\n";
//    cout << "\n> " << file.tellg() << "\n" << endl;
}

int main(int argc, char* argv[])
{
    ofstream new_file;
    new_file.open("test.txt");
    new_file.close();

    fstream file("test.txt", ios::in | ios::out);
    if (!file.is_open())
    {
        cout << "error file not opened" << endl;
        return 0;
    }

    file << "ABCD";
    display_txt_file(file);

    file.seekp(0);

    file << "ABCD\nE";
    display_txt_file(file);

    return 0;
}

当我在 Windows 上运行它时,我得到以下输出:

tellg: 0| 'A' tellg: 1| 'B' tellg: 2| 'C' tellg: 3| 'D' tellg: 4|
tellg: 0| 'A' tellg: 1| 'B' tellg: 2| 'C' tellg: 3| 'D' tellg: 4| '<\n>' tellg: 6| 'E' tellg: 7|

因此,直到新行匹配的所有内容都完全符合我们的预期。然后换行符扩展为两个字符,然后是E. 但是,在我们阅读了“A”之后,tellg它返回了1,而不是2,正如问题中所声称的那样。


推荐阅读