使用 iostreams 读取文件的一部分

read part of a file with iostreams

本文关键字:一部分 文件 读取 iostreams 使用      更新时间:2023-10-16

我可以打开一个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 接口,如果存在的话(。