在不使用缓冲区的情况下,将数据从fstream复制到stringstream?

27

我是否可以将fstream(一个文件)中的数据传输到stringstream(内存流)中?

目前,我正在使用缓冲区,但这需要双倍的内存,因为您需要将数据复制到缓冲区,然后将缓冲区复制到stringstream中,在删除缓冲区之前,数据在内存中被复制。

std::fstream fWrite(fName,std::ios::binary | std::ios::in | std::ios::out);  
    fWrite.seekg(0,std::ios::end); //Seek to the end  
    int fLen = fWrite.tellg(); //Get length of file  
    fWrite.seekg(0,std::ios::beg); //Seek back to beginning  
    char* fileBuffer = new char[fLen];  
    fWrite.read(fileBuffer,fLen);  
    Write(fileBuffer,fLen); //This writes the buffer to the stringstream  
    delete fileBuffer;`

请问有人知道如何在不使用中间缓冲区的情况下将整个文件写入stringstream吗?


有什么意义呢?你是想提高吞吐量吗?如果是的话,你可能需要放弃使用 fstream,因为 iostreams 很慢。你是想减少内存占用吗?分块读取文件可能会有所帮助。 - Ben Voigt
5个回答

37
 ifstream f(fName);
 stringstream s;
 if (f) {
     s << f.rdbuf();    
     f.close();
 }

32
// need to include <algorithm> and <iterator>, and of course <fstream> and <sstream>
ifstream fin("input.txt");
ostringstream sout;
copy(istreambuf_iterator<char>(fin),
     istreambuf_iterator<char>(),
     ostreambuf_iterator<char>(sout));

@Charles -- 尽管如此,我认为这就是他的意图。他不想分配一个新的char数组。他想直接从fstream对象读取到stringstream对象中。 - Benjamin Lindley
@BenVoigt,你是对的 - 我误读了OP。我以为他们在问如何直接读取stringstream。 - Charles Salvia
这似乎是我正在寻找的!@PigBen,你说得对,我不想使用char数组。我有一个问题: copy方法是否考虑stringstream的当前写入位置?如果我使用tellp(8),然后使用copy()它仍然有效吗,还是会从stringstream的开头开始写入? 编辑:我自己尝试了一下,它似乎非常好用。谢谢! - Brad
2
不过,我更喜欢pinkfloydx的解决方案(由Andre制作成完整示例)。std :: copy将不得不一次移动一个元素,而operator <<(istream&)可能会快得多。 - Ben Voigt
@Ben Voigt:我也是这样想的。事实上,我之前并不知道可以如此轻松地完成。我的测试结果显示存在轻微差异。在一个50k文件上,分别使用两种方法进行10次复制,他的平均每个副本耗时1.45秒,而我的平均耗时为1.62秒。 - Benjamin Lindley
你是认真的吗?磁盘到内存的速度只有35kB/sec?这太90年代了。巧合的是,今天早些时候我开始将我的一些代码从ifstream重写为MapViewOfFile,因为我在上周五进行的分析显示fstream花费了大量时间。完全有10%的运行时间是ofstream获取锁(当文件仅从单个线程使用时)。简直荒谬。 - Ben Voigt

10
ostream的文档中,有多个重载的operator<<。其中之一需要一个streambuf*并读取所有流缓冲区的内容。
以下是一个示例用法(已编译和测试):
#include <exception>
#include <iostream>
#include <fstream>
#include <sstream>

int main ( int, char ** )
try
{
        // Will hold file contents.
    std::stringstream contents;

        // Open the file for the shortest time possible.
    { std::ifstream file("/path/to/file", std::ios::binary);

            // Make sure we have something to read.
        if ( !file.is_open() ) {
            throw (std::exception("Could not open file."));
        }

            // Copy contents "as efficiently as possible".
        contents << file.rdbuf();
    }

        // Do something "useful" with the file contents.
    std::cout << contents.rdbuf();
}
catch ( const std::exception& error )
{
    std::cerr << error.what() << std::endl;
    return (EXIT_FAILURE);
}

1
如果您正在使用 Poco,那么这很简单:

#include <Poco/StreamCopier.h>

ifstream ifs(filename);
string output;
Poco::StreamCopier::copyToString(ifs, output);

1

使用C++标准库的唯一方法是使用ostrstream而不是stringstream

您可以使用自己的char缓冲区构造一个ostrstream对象,它将接管缓冲区(因此不需要再复制)。

请注意,strstream头文件已被弃用(尽管它仍然是C++03的一部分,并且很可能始终可用于大多数标准库实现),如果您忘记对提供给ostrstream的数据进行空终止,则会遇到大麻烦。这也适用于流运算符,例如:ostrstreamobject << some_data << std::ends;std::ends将数据空终止)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接