为了将
ifstream
(或实际上是任何输入流)伪装成行为类似于迭代器的形式,您需要使用
istream_iterator
或
istreambuf_iterator
模板类。前者对于需要考虑格式的文件非常有用。例如,一个充满空格分隔整数的文件可以按以下方式读入vector的迭代器范围构造函数中:
#include <fstream>
#include <vector>
#include <iterator>
using namespace std;
int main(int argc, char** argv)
{
ifstream infile("my-file.txt");
istream_iterator<int> infile_begin(infile);
istream_iterator<int> infile_end;
vector<int> my_ints(infile_begin, infile_end);
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;
vector<char> char_input(input_begin, input_end);
input.close();
unsigned long* converted = reinterpret_cast<unsigned long*>(&char_input[0]);
size_t num_long_elements = char_input.size() * sizeof(char) / sizeof(unsigned long);
vector<unsigned long> long_input(converted, converted + num_long_elements);
return 0;
}
现在,我个人不太喜欢这种解决方案(使用reinterpret_cast
,暴露char_input
的数组),但我对istreambuf_iterator
不够熟悉,无法舒适地使用一个模板化为64位字符的迭代器,这将使这个问题变得更容易。
istream_iterator
是您的好朋友。 - Dawson