c++ - 等效于 C++ 中用于缓冲读取的 python 生成器

标签 c++ python algorithm file io

Guido Van Rossum 在这个 article 中展示了 Python 的简单性并利用此函数缓冲读取未知长度的文件:

def intsfromfile(f):
    while True:
        a = array.array('i')
        a.fromstring(f.read(4000))
        if not a:
            break
        for x in a:
            yield x

出于速度原因,我需要在 C++ 中做同样的事情!我有许多文件包含我需要合并的无符号 64 位整数的排序列表。我找到了这件漂亮的 code用于合并 vector 。

我被困在如何为未知长度的文件制作一个 ifstream 将自己呈现为一个 vector ,它可以愉快地迭代直到文件末尾到达。有什么建议么?我是否使用 istreambuf_iterator 建立了正确的树?

最佳答案

为了伪装 ifstream (或者实际上,任何输入流)以类似于迭代器的形式,你想使用 istream_iteratoristreambuf_iterator模板类。前者对于格式很重要的文件很有用。例如,一个充满空白分隔整数的文件可以读入 vector 的迭代器范围构造函数,如下所示:

#include <fstream>
#include <vector>
#include <iterator> // needed for istream_iterator

using namespace std;

int main(int argc, char** argv)
{
    ifstream infile("my-file.txt");

    // It isn't customary to declare these as standalone variables,
    // but see below for why it's necessary when working with
    // initializing containers.
    istream_iterator<int> infile_begin(infile);
    istream_iterator<int> infile_end;

    vector<int> my_ints(infile_begin, infile_end);

    // You can also do stuff with the istream_iterator objects directly:
    // Careful! If you run this program as is, this won't work because we
    // used up the input stream already with the vector.

    int total = 0;
    while (infile_begin != infile_end) {
        total += *infile_begin;
        ++infile_begin;
    }

    return 0;
}

istreambuf_iterator用于一次读取一个字符的文件,而不考虑输入的格式。也就是说,它将返回所有字符,包括空格、换行符等。根据您的应用,这可能更合适。

注意:Scott Meyers 在 Effective STL 中解释了为什么 istream_iterator 的单独变量声明以上是需要的。通常,你会做这样的事情:

ifstream infile("my-file.txt");
vector<int> my_ints(istream_iterator<int>(infile), istream_iterator<int>());

但是,C++ 实际上以一种非常奇怪的方式解析第二行。它将其视为名为 my_ints 的函数的声明它接受两个参数并返回一个 vector<int> .第一个参数的类型是 istream_iterator<int>并命名为infile (括号被忽略)。第二个参数是一个没有名称的函数指针,它采用零参数(因为括号)并返回类型为 istream_iterator<int> 的对象。 .

很酷,但如果你不注意的话也会很恼火。


编辑

这是一个使用 istreambuf_iterator 的例子读取端到端排列的 64 位数字文件:

#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>

using namespace std;

int main(int argc, char** argv)
{
    ifstream input("my-file.txt");
    istreambuf_iterator<char> input_begin(input);
    istreambuf_iterator<char> input_end;

    // Fill a char vector with input file's contents:
    vector<char> char_input(input_begin, input_end);
    input.close();

    // Convert it to an array of unsigned long with a cast:
    unsigned long* converted = reinterpret_cast<unsigned long*>(&char_input[0]);
    size_t num_long_elements = char_input.size() * sizeof(char) / sizeof(unsigned long);

    // Put that information into a vector:
    vector<unsigned long> long_input(converted, converted + num_long_elements);

    return 0;
}

现在,我个人比较不喜欢这个解决方案(使用 reinterpret_cast ,公开 char_input 的数组),但我对 istreambuf_iterator 还不够熟悉舒适地使用一个超过 64 位的模板化字符,这将使这变得容易得多。

关于c++ - 等效于 C++ 中用于缓冲读取的 python 生成器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4685862/

相关文章:

c++ - 各种大小的 c/c++ 中的 int

c++ - 运算符重载 - 重载 *

python - python中的列表项排列

python多处理: sleep statement killed?

java - 找到相交轨迹的最佳方法

java - java中子类方法中无法访问抽象类对象的属性

c++ - 以下初始化在 C++ 中是否等效

c++ - 实现真值表的一般模式

python - 如何增加预定义 x 范围的 x 轴上显示的厚度数量?

algorithm - KMV算法中多个不同大小的K最小值集的并集