提问人:mkluwe 提问时间:10/28/2023 更新时间:10/28/2023 访问量:43
'std::fstream' 和 'std::stringstream' 在读写用法中是否有不同的行为?
Is there different behaviour of `std::fstream` and `std::stringstream` in read-write-usage?
问:
我尝试了以下操作来覆盖“就地”流:
#include <cstdio>
#include <fstream>
#include <iostream>
#include <sstream>
void e(std::iostream &s) {
unsigned char c;
while (s) {
s.get(reinterpret_cast<char &>(c));
++c;
s.put(reinterpret_cast<char &>(c));
}
}
int main() {
// test for `stringstream`
std::stringstream s("test");
e(s);
std::cout << s.str() << std::endl;
// setup temporary file
auto n = std::tmpnam(nullptr);
{
std::ofstream f(n);
f << "test";
}
// test for `fstream`
{
std::fstream f(n);
e(f);
}
{
std::string buf;
std::ifstream f(n);
f >> buf;
std::cout << buf << std::endl;
}
}
令我惊讶的是,这输出(见 https://godbolt.org/z/qa881v78q)
uftu
tust
按预期被覆盖,而文件内容仅在一个位置更改。似乎改变了写入位置,并且由于某种原因,流在那之后变坏了。stringstream
get
我想我在这里遗漏了一些非常基本的东西,但我真的很想用 a 作为一个简单的模拟,因为两者都是 s。stringstream
fstream
iostream
答:
3赞
Remy Lebeau
10/28/2023
#1
字符串流有 1 个数据缓冲区,但在该缓冲区中具有单独的读/写位置。
文件流在其数据中只有 1 个读/写位置。当您读取或写入文件时,该位置会按读取/写入的字节数提前。
要执行您正在尝试的操作,您必须在每次读取后将写入位置恢复到上一个位置,以覆盖您刚刚读取的字符。
评论
0赞
mkluwe
10/28/2023
好的,实际的建议是什么?在阅读之前和之后添加似乎有效(见 godbolt.org/z/jh3MdjWda)。可以做得更聪明吗?auto pos = s.tellg();
s.seekp(pos);
0赞
Remy Lebeau
10/29/2023
@mkluwe这基本上是你需要做的。您可以尝试,但这仅适用于具有共享读/写位置的文件流,而不适用于具有单独读/写位置的其他流。s.seekp(-1, std::ios_base::cur)
评论