читать часть файла с помощью iostreams - PullRequest
7 голосов
/ 23 января 2012

Могу ли я открыть ifstream (или установить существующий каким-либо образом), чтобы прочитать только часть файла?Например, я хотел бы, чтобы мой ifstream прочитал файл из байта 10–50. Поиск позиции 0 будет позицией 10 в реальности, чтение предыдущей позиции 40 (50 в действительности) приведет к EOF и т. Д.. Возможно ли это каким-либо образом?

Ответы [ 3 ]

7 голосов
/ 23 января 2012

Это определенно может быть сделано путем реализации буфера потоков фильтрации: вы бы взяли из 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, вместо этого настраивая буфер потока.

5 голосов
/ 23 января 2012

Вы можете прочитать нужные байты в строку или массив символов, затем вы можете использовать эту строку с потоком 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));
2 голосов
/ 23 января 2012

Возможно, вы захотите реализовать свой собственный класс чтения потоков (предпочтительно через некоторый интерфейс ifstream, если таковой существует).

...