【发布时间】:2012-01-22 20:17:03
【问题描述】:
我可以打开一个ifstream(或以任何方式设置一个现有的)来只读取文件的一部分吗?例如,我想让我的ifstream 从字节 10 到 50 读取文件。寻找位置 0 将是实际位置 10,读取过去的位置 40(实际上是 50)将导致 EOF 等. 这有可能吗?
【问题讨论】:
我可以打开一个ifstream(或以任何方式设置一个现有的)来只读取文件的一部分吗?例如,我想让我的ifstream 从字节 10 到 50 读取文件。寻找位置 0 将是实际位置 10,读取过去的位置 40(实际上是 50)将导致 EOF 等. 这有可能吗?
【问题讨论】:
这绝对可以通过实现过滤流缓冲区来完成:您将从std::streambuf 派生并将要公开的范围和底层流缓冲区(嗯,指向它的指针)作为参数。然后你会寻找起始位置。被覆盖的underflow() 函数将从底层流缓冲区读取到其缓冲区,直到消耗了所需的字符数。这是一个有些粗糙且完全未经测试的版本:
#include <streambuf>
struct rangebuf: std::streambuf {
rangebuf(std::streampos start,
size_t size,
std::streambuf* sbuf):
size_(size), sbuf_(sbuf)
{
sbuf->seekpos(start, std::ios_base::in);
}
int underflow() {
size_t r(this->sbuf_->sgetn(this->buf_,
std::min<size_t>(sizeof(this->buf_), this->size_));
this->size -= r;
this->setg(this->buf_, this->buf_, this->buf_ + r);
return this->gptr() == this->egptr()
? traits_type::eof()
: traits_type::to_int_type(*this->gptr());
}
size_t size_;
std::streambuf* sbuf_;
};
您可以使用指向此流缓冲区实例的指针来初始化std::istream。如果这是一个反复出现的需求,您可能希望创建一个派生自 std::istream 的类,以设置流缓冲区。
【讨论】:
您可以将您想要的字节读入字符串或字符数组,然后您可以将该字符串与 istringstream 一起使用,并使用它来代替您的 ifstream。示例:
std::ifstream fin("foo.txt");
fin.seekg(10);
char buffer[41];
fin.read(buffer, 40);
buffer[40] = 0;
std::istringstream iss(buffer);
for (std::string s; iss >> s; ) std::cout << s << '\n';
如果你需要处理二进制文件,你也可以这样做:
std::ifstream fin("foo.bin", std::ios::binary | std::ios::in);
fin.seekg(10);
char buffer[40];
fin.read(buffer, 40);
std::istringstream(std::string(buffer, buffer+40));
【讨论】:
您可能想要实现自己的流阅读器类(如果存在的话,最好通过一些 ifstream 接口)。
【讨论】: