提问人:Tomáš Nadrchal 提问时间:9/2/2023 更新时间:9/2/2023 访问量:40
读取文件中的结束字符问题
Endline character problem in reading files
问:
我有一个函数,可以将文件读取到缓冲区,然后通过可变参数模板逐行解析到容器。std::vector<char>
我发现带有字符的缓冲区有问题。\n
这是一个输入文件 (UTF-8): H,1, H,2,
这是十六进制的: 48 2C 31 2C 0D 0A 48 2C 32 2C 0D 0A
H , 1 , ..H , 2 , ..
现在我有了将其导入缓冲区的代码(故意省略了不同的检查):
std::ifstream in ("file.txt");
in.seekg(0, std::ios::end);
std::streampos fileLength = in.tellg();
in.seekg(0, std::ios::beg);
std::vector<char> buf (fileLength);
in.read(&buf[0], fileLength);
in.close ();
但是,如果我以这种方式打印缓冲区(使用相同的原理导入到容器中):
void printHex (std::vector<char>& buffer)
{
std::size_t noOfChar {buffer.size()};
std::cout << "Number of chars: " << noOfChar << "\n";
for (std::size_t i {0}; i < noOfChar; ++i)
{
std::cout << buffer[i];
}
std::cout << "\n";
for (std::size_t i {0}; i < noOfChar; ++i)
{
sum += (buffer[i]);
std::cout << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(buffer[i]) << " ";
}
std::cout << std::endl;
}
我明白了:
字符数: 12 H,1, H,2, 48 2c 31 2c 0a 48 2c 32 2c 0a 00 00
我尝试了使用更多数据的不同输入,很明显,十六进制 0D 0A 仅作为 0A 读入缓冲区。 解决方案可能相对简单,在缓冲区末尾修剪所有多余的 00,以便以后不会被函数解析行所采用。
但我的问题是:
- 为什么这样做,“\n”字符将作为 0D 0A 保存到文件中,并作为“\n”字符导入回
- 有没有更好的方法通过导入到streamstring缓冲区来处理“\n”?
答:
对于第一个问题,这涉及到 ASCII 换行字符的历史。在 Linux 上,换行符通常由字符 () 表示。在 Windows 上,换行符由 () 字符表示(将光标返回到行的开头,后跟 () 字符(将光标放在同一列下方的行上。'\x0a'
\n
\x0d
\r
\x0a
\n
在 C++ 中,为了提供抽象,对于文本流,它们会进行隐式转换。当您键入时,它会将其转换为不同的平台或在不同的平台上转换。如果您尝试读取二进制文件,这可能会导致问题。这就是为什么输入流会为要打开的流类型(文本或二进制)使用第二个标志。\n
\n
\r\n
为了回答第二个问题,只需将 slap 作为第二个参数,这将以二进制形式打开流,并且应该避免隐式行尾转换。std::ios::binary
std::ifstream in("file.txt", std::ios::binary);
如果您尝试将整个文件读入缓冲区并通过查找来获取其长度,我建议以二进制模式打开所有文件:以这种方式获取文本文件的长度是危险的,并且可能导致与读取未初始化内存相关的错误(您正在读取的字符比实际的要少)。
这也意味着您必须手动处理。\r
评论
\r\n
\n
ios::binary
std::istream_iterator
>>