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这个很好的部分.
我坚持如何为一个未知长度的文件创建一个ifstream作为一个向量,可以愉快地迭代,直到到达文件的末尾.有什么建议?我用istreambuf_iterator吠叫正确的树吗?
最佳答案 为了在一个像迭代器一样的形式中伪装ifstream(或者实际上是任何输入流),你想要使用istream_iterator或istreambuf_iterator模板类.前者对于格式化问题的文件非常有用.例如,一个包含空白分隔整数的文件可以读入向量的迭代器范围构造函数,如下所示:
#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的函数的声明,它接受两个参数并返回一个向量< int>.第一个参数的类型为istream_iterator< int>并被命名为infile(被忽略的parantheses).第二个参数是一个没有名称的函数指针,它接受零参数(由于parantheses)并返回一个类型为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位的字符,这将使这更容易.