std :: ifstream缓冲区缓存

led*_*kol 8 c++ sorting performance file buffering

在我的应用程序中,我正在尝试合并已排序的文件(当然保持它们排序),因此我必须遍历两个文件中的每个元素以将最小值写入第三个.这对大文件来说非常慢,只要我没有看到任何其他选择(迭代必须完成)我正在尝试优化文件加载.我可以使用一些RAM,我可以用它来缓冲.我的意思是不是每次读取两个文件中的4个字节,而是每次读取100Mb之类的东西,然后使用该缓冲区,直到缓冲区中没有元素,然后我将再次重新填充缓冲区.但我想ifstream已经这样做了,它会给我更多的表现吗?有什么理由吗?如果fstream有,也许我可以改变那个缓冲区的大小?

添加

我当前的代码看起来像那样(伪代码)

// this is done in loop
int i1 = input1.read_integer();
int i2 = input2.read_integer();
if (!input1.eof() && !input2.eof())
{
   if (i1 < i2)
   {
      output.write(i1);
      input2.seek_back(sizeof(int));
   } else
      input1.seek_back(sizeof(int));
      output.write(i2);
   }
} else {
   if (input1.eof())
      output.write(i2);
   else if (input2.eof())
      output.write(i1);
}
Run Code Online (Sandbox Code Playgroud)

我不喜欢的是

  • seek_back - 我必须回到以前的位置,因为没有办法偷看4个字节
  • 从文件中读取太多
  • 如果其中一个流在EOF中,它仍然继续检查该流而不是将另一个流的内容直接输出到输出,但这不是一个大问题,因为块大小几乎总是相等的.

你能建议改进吗?

谢谢.

dav*_*vka 5

如果不进入关于流缓冲区的讨论,您可以seek_back通过执行以下操作来摆脱并通常使代码更简单:

using namespace std;
merge(istream_iterator<int>(file1), istream_iterator<int>(),
           istream_iterator<int>(file2), istream_iterator<int>(),
           ostream_iterator<int>(cout));
Run Code Online (Sandbox Code Playgroud)

编辑:

添加了二进制功能

#include <algorithm>
#include <iterator>
#include <fstream>
#include <iostream>

struct BinInt
{
    int value;
    operator int() const { return value; }
    friend std::istream& operator>>(std::istream& stream, BinInt& data)
    {
        return stream.read(reinterpret_cast<char*>(&data.value),sizeof(int));
    }
};

int main()
{
    std::ifstream   file1("f1.txt");
    std::ifstream   file2("f2.txt");

    std::merge(std::istream_iterator<BinInt>(file1), std::istream_iterator<BinInt>(),
               std::istream_iterator<BinInt>(file2), std::istream_iterator<BinInt>(),
               std::ostream_iterator<int>(std::cout));
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*ork 0

除非您的数据有一些非常特殊的内容,否则您不太可能改进 std::fstream 对象中内置的缓冲。

std::fstream 对象被设计为对于通用文件访问非常有效。听起来您并没有通过一次访问 4 个字节的数据来执行任何特殊操作。您始终可以分析代码以查看代码中实际时间花费在哪里。

也许如果您与我们分享代码,我们可能会发现一些严重的低效率问题。

编辑:

我不喜欢你的算法。在流上向后和向前查找可能很困难,尤其是当数字超出缓冲区边界时。我每次循环时只会读取一个数字。

试试这个:
注意:这不是最佳的(它假设数字的流输入(而你的看起来是二进制的))但我相信你可以使用它作为起点。

#include <fstream>
#include <iostream>

// Return the current val (that was the smaller value)
// and replace it with the next value in the stream.
int getNext(int& val, std::istream& str)
{
    int result = val;
    str >> val;

    return result;
}

int main()
{
    std::ifstream   f1("f1.txt");
    std::ifstream   f2("f2.txt");
    std::ofstream   re("result");

    int v1;
    int v2;

    f1 >> v1;
    f2 >> v2;

    // While there are values in both stream
    // Output one value and replace it using getNext()
    while(f1 && f2)
    {
        re << (v1 < v2)? getNext(v1, f1) : getNext(v2, f2);
    }
    // At this point one (or both) stream(s) is(are) empty.
    // So dump the other stream.
    for(;f1;f1 >> v1)
    {
        // Note if the stream is at the end it will
        // never enter the loop
        re << v1;
    }
    for(;f2;f2 >> v2)
    {
        re << v2;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Martin,你想搞笑吗?众所周知,“fstream”的几种广泛使用的实现(包括 gcc 和 Visual C++)都具有糟糕的性能。 (3认同)