'std::fstream' 和 'std::stringstream' 在读写用法中是否有不同的行为?

Is there different behaviour of `std::fstream` and `std::stringstream` in read-write-usage?

提问人:mkluwe 提问时间:10/28/2023 更新时间:10/28/2023 访问量:43

问:

我尝试了以下操作来覆盖“就地”流:

#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

按预期被覆盖,而文件内容仅在一个位置更改。似乎改变了写入位置,并且由于某种原因,流在那之后变坏了。stringstreamget

我想我在这里遗漏了一些非常基本的东西,但我真的很想用 a 作为一个简单的模拟,因为两者都是 s。stringstreamfstreamiostream

C++ 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)