ofstream :: operator<<(streambuf)是一种复制文件的慢速方法

时间:2011-08-30 22:56:15

标签: c++ fstream

我需要一个跨平台,没有外部库,复制文件的方式。在我的第一次传递中,我提出了(错误处理省略):

char buffer[LEN];
ifstream src(srcFile, ios::in | ios::binary);
ofstream dest(destFile, ios::out | ios::binary);

while (!src.eof()) {
  src.read(buffer, LEN);
  dest.write(buffer, src.gcount());
}

这很好用,我确切知道它在做什么。

然后我在stackoverflow上发现了一个帖子(抱歉,现在找不到链接),说我可以用以下代码替换所有上面的代码:

dest << src.rdbuf();

这很好而且紧凑,但隐藏了很多关于它正在做的事情。事实证明它非常慢因为ofstream :: operator&lt;&lt;(streambuf)的实现一次移动1个字符(使用snetxc()/ sputc())。

我有办法让这种方法更快吗?我原来的方法有缺点吗?

更新:在Windows上使用运算符&lt;&lt;(streambuf)效率低下。 .read()/。write()循环看起来总是比运算符&lt;&lt;。

更好

此外,在上面的代码中更改缓冲区的大小不会影响对硬盘驱动器的读写大小。为此,您需要使用stream.rdbuf() - &gt; pubsetbuf()设置缓冲区。

3 个答案:

答案 0 :(得分:10)

我想知道你的fstream默认是否是无缓冲的。 GCC 4.5.2默认使用内部缓冲区,但我不认为标准要求。您是否尝试过使用pubsetbuf(见下文)为您的输入/输出流设置缓冲区。

对我的系统进行快速测试,如果我将LEN设置为0(因此无缓冲),则需要10秒才能复制1 MB文件。使用4k缓冲区,可在不到一秒的时间内完成。

#include <iostream>
#include <fstream>

int main() {
  using namespace std;
  const char* srcFile = "test.in";
  const char* destFile = "test.out";

  ifstream src;
  ofstream dest;

  const int LEN=8192;
  char buffer_out[LEN];
  char buffer_in[LEN];
  if (LEN) {
    src.rdbuf()->pubsetbuf(buffer_in, LEN );
    dest.rdbuf()->pubsetbuf(buffer_out, LEN);
  } else {
    src.rdbuf()->pubsetbuf(NULL, 0 );
    dest.rdbuf()->pubsetbuf(NULL, 0);
  }
  src.open(srcFile, ios::in | ios::binary);
  dest.open(destFile, ios::out | ios::binary);
  dest << src.rdbuf();

}

答案 1 :(得分:1)

当然src.rdbuf方法较慢。它正在同时读写 。除非您要复制到不同的硬盘或某种形式的网络或附加存储,否则这比读取块然后编写块要慢。

仅仅因为代码是紧凑的并不会使它更快。


由于你不能为operator<<重载std::filebuf(因为它已经超载),所以你无能为力。最好只使用效果合理的方法。

答案 2 :(得分:1)

尝试使用C stdio API,在许多实现中通常会更快(对于某些数字,请参阅this thread),但并非总是如此。例如:

// Error checking omitted for expository purposes
char buffer[LEN];
FILE *src = fopen(srcFile, "rb");
FILE *dest = fopen(destFile, "wb");

int n;
while ((n = fread(buffer, 1, LEN, src)) > 0)
{
    fwrite(buffer, 1, n, dest);
}

fclose(src);
fclose(dest);