我的问题类似于这个问题,但我没有找到任何关于C++的参考资料。
有一个大文件列表需要读取和处理。创建一个输入流的最佳方法是什么?该输入流将逐个从文件中获取数据,在前一个文件结束时自动打开下一个文件。此流将被传递给一个处理函数,该函数顺序读取可变大小的块,跨越文件边界。
有一个大文件列表需要读取和处理。创建一个输入流的最佳方法是什么?该输入流将逐个从文件中获取数据,在前一个文件结束时自动打开下一个文件。此流将被传递给一个处理函数,该函数顺序读取可变大小的块,跨越文件边界。
std::basic_streambuf
的类型。这个类型有许多神秘的virtual
成员函数,其中与你相关的是showmanyc()
、underflow()
、uflow()
和xsgetn()
。你需要重载它们,在溢出时自动打开列表中的下一个文件(如果有的话)。std::filebuf
,只需保留一个deque<string>
的下一个需要读取的文件即可:class multifilebuf : public std::filebuf
{
public:
multifilebuf(std::initializer_list<std::string> filenames)
: next_filenames(filenames.begin() + 1, filenames.end())
{
open(*filenames.begin(), std::ios::in);
}
protected:
std::streambuf::int_type underflow() override
{
for (;;) {
auto res = std::filebuf::underflow();
if (res == traits_type::eof()) {
// done with this file, move onto the next one
if (next_filenames.empty()) {
// super done
return res;
}
else {
// onto the next file
close();
open(next_filenames.front(), std::ios::in);
next_filenames.pop_front();
continue;
}
}
else {
return res;
}
}
}
private:
std::deque<std::string> next_filenames;
};
multifilebuf mfb{"file1", "file2", "file3"};
std::istream is(&mfb);
std::string word;
while (is >> word) {
// transaparently read words from all the files
}
underflow()
即可。 - Barry对于一个简单的解决方案,可以使用boost
的join和istream迭代器来处理文件。我不知道当前C++库中是否存在类似的函数,但在TS Rangesv3中可能存在。
您也可以自己编写:编写join本身是完全可行的。
我会将其编写为“展平”输入迭代器——一个迭代器,它遍历一系列范围的内容。该迭代器将跟踪未来的范围和当前元素的迭代器。
这里是一个非常简单的zip迭代器,可以让您了解需要编写的代码量(zip迭代器是一个不同的概念,这只适用于for(:)
循环)。
以下是使用C++14实现的草图:
template<class It>
struct range_t {
It b{};
It e{};
It begin() const { return b; }
It end() const { return e; }
bool empty() const { return begin()==end(); }
};
template<class It>
struct range_of_range_t {
std::deque<range_t<It>> ranges;
It cur;
friend bool operator==(range_of_range_t const& lhs, range_of_range_t const& rhs) {
return lhs.cur==rhs.cur;
}
friend bool operator!=(range_of_range_t const& lhs, range_of_range_t const& rhs) {
return !(lhs==rhs);
}
void operator++(){
++cur;
if (ranges.front().end() == cur) {
next_range();
}
}
void next_range() {
while(ranges.size() > 1) {
ranges.pop_front();
if (ranges.front().empty()) continue;
cur = ranges.front().begin();
break;
}
}
decltype(auto) operator*() const {
return *cur;
}
range_of_range_t( std::deque<range_t<It>> in ):
ranges(std::move(in)),
cur{}
{
// easy way to find the starting cur:
ranges.push_front({});
next_range();
}
};
迭代器需要改进,它应该支持所有的迭代器公理。而正确获取结束迭代器也需要一些工作。
这不是一个流,而是一个迭代器。
cat input_file*.dat | myprogram
。但是,如果没有更多细节(即文件是否都在一个可全局匹配的目录中,还是分散在各个地方,或者顺序需要不同),那么很难说更多了... - twalbergstd::istream
的新类,其中包含一个std::vector
的std::ifstream
,它会在 EOF 或读取失败时自动切换到下一个。 - KABoissonneault