ostream_iterator用于将数字数据写入文件的性能?

时间:2010-01-02 20:46:57

标签: c++ stl

我有各种带有数值数据的std :: vector实例,主要是int16_t,int32_t等。我想以尽可能快的方式将这些数据转储到文件中。如果我使用ostream_iterator,它会在一次操作中写入整个内存块,还是会迭代向量的元素,为每个元素发出写操作?

7 个答案:

答案 0 :(得分:2)

转储向量的最快(但最可怕)方法是使用ostream :: write在一个操作中编写它:

   os.write( (char *) &v[0], v.size() * sizeof( value_type) );

你可以使用模板函数使它更好一些:

template <typename T> 
std::ostream & DumpVec( std::ostream & os, const std::vector <T> & v ) {
    return os.write( &v[0], v.size() * sizeof( T ) );
}

允许你说出这样的话:

vector <unsigned int> v;
ofstream f( "file.dat" );
...
DumpVec( f, v );

重新读回来会有点问题,除非你以某种方式给写的前缀大小(或者矢量是固定大小的),然后你就会在不同的endian和/或32上遇到问题v 64位架构,正如几个人所指出的那样。

答案 1 :(得分:2)

在我熟悉的任何实现中,流迭代器和向量肯定不会使用块副本。例如,如果向量项类型是类而不是POD,则直接复制将是一件坏事。我怀疑ostream也会格式化输出,而不是直接写入值(即ascii而不是二进制输出)。

您可能会更好地使用boost::copy,因为它在可能的情况下专门针对块写入进行了优化,但最实用的解决方案是使用&v[0]直接对矢量内存进行操作。

答案 2 :(得分:2)

我知道的大多数ofstream实现都会缓冲数据,因此您可能不会最终执行过多的写操作。 ofstream()中的缓冲区必须在实际写入完成之前填满,并且大多数OS的缓冲区文件数据也在此之下。这些相互作用在C ++应用程序级别上并不透明;缓冲区大小的选择等由实现决定。

C ++确实提供了一种向ostream的{​​{3}}提供自己的缓冲区的方法。您可以尝试这样调用streambuf

char *mybuffer = new char[bufsize];
os.rdbuf()->pubsetbuf(mybuffer, bufsize);

缺点是这不一定会做任何事情。一些实现pubsetbuf

如果您想要缓冲内容但仍然使用ostream_iterator,那么您拥有的另一个选项是使用ostringstream,例如:

ostringstream buffered_chars;
copy(data.begin(), data.end(), ostream_iterator<char>(buffered_chars, " ");
string buffer(buffered_chars.str());

然后,一旦缓冲了所有数据,就可以使用一个大ostream::write(),POSIX I / O等编写整个缓冲区。

但是,这仍然很慢,因为您正在进行格式化输出,并且您必须同时在内存中存储两个数据副本:原始数据和格式化的缓冲数据。如果你的应用程序已经超出了内存的限制,这不是最好的方法,你可能最好使用ofstream给你的内置缓冲。

最后,如果您真的想要性能,最快的方法是使用ostream::write()作为just ignore it将原始内存转储到磁盘,或者使用操作系统的I / O功能。这里的缺点是您的数据没有格式化,您的文件可能不是人类可读的,并且在具有与您编写的字节序不同的字节顺序的体系结构上不易读取。但它可以快速将数据传输到磁盘,而无需为应用程序添加内存要求。

答案 3 :(得分:0)

我猜这是依赖于实现的。如果你没有得到你想要的性能,你可以随时memmap结果文件并将std :: vector数据memcpy到memmapped文件。

答案 4 :(得分:0)

如果使用ofstream构造ostream_iterator,将确保输出被缓冲:

ofstream ofs("file.txt");
ostream_iterator<int> osi(ofs, ", ");
copy(v.begin(), v.end(), osi);

ofstream对象是缓冲的,因此写入流的任何内容都会在写入磁盘之前得到缓冲。

答案 5 :(得分:0)

它将迭代元素。迭代器不会让你一次弄乱多个项目。此外,IIRC,它会将您的整数转换为ASCII表示。

如果你想通过ostream一步一步地将矢量(二进制)中的所有内容写入文件,你需要类似的东西:

template<class T>
void WriteArray(std::ostream& os, const std::vector<T>& v)
{
    os.write(static_cast<const char*>(&v[0]), v.size() * sizeof(T));
}

答案 6 :(得分:0)

您还没有写过如何使用迭代器(我假设std::copy)以及您是要编写数据二进制文件还是编写字符串。

我希望std::copy能够很好地实现POD的std::memcpy和迭代器的Dumbum指针(例如Dinkumware)。但是,使用ostream迭代器,我认为std::copy的任何实现都不会这样做,因为它没有直接访问ostream的缓冲区来写入。

然而,溪流本身也是缓冲的。

最后,我会先编写最简单的代码,然后测量一下。如果它足够快,继续下一个问题。如果这是那种不够快的代码,那么无论如何你都必须采用特定于操作系统的技巧。