2012-01-22 13 views
6

Czy mogę otworzyć ifstream (lub ustawić istniejący w jakikolwiek sposób), aby odczytać tylko część pliku? Na przykład, chciałbym, aby mój ifstream odczytał plik z bajtu od 10 do 50. Znalezienie pozycji 0 byłoby w rzeczywistości pozycją 10, odczytanie pozycji z poprzedniej pozycji 40 (50 w rzeczywistości) powtórzyłoby się w EOF itd. Czy to możliwe? w jakikolwiek sposób?odczytać część pliku za pomocą iostreams

Odpowiedz

7

Z pewnością można tego dokonać przez zaimplementowanie filtrującego bufora strumieniowego: można wyprowadzić z std::streambuf i zabrać zakres, który chcesz eksponować, i bazowy bufor strumienia (cóż, wskaźnik do niego) jako argumenty. Następnie szukałbyś lokalizacji początkowej. Zastąpiona funkcja underflow() odczytywałaby z bazowego bufora strumieniowego do swojego bufora, dopóki nie zużyła tylu znaków, ile by było pożądanych. Oto nieco szorstkie i całkowicie niesprawdzone wersja:

#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_; 
}; 

Można użyć wskaźnika do wystąpienia tego bufora strumienia initialuze się std::istream. Jeśli jest to powtarzające się zapotrzebowanie, możesz utworzyć klasę pochodną od std::istream, ustawiając zamiast niej bufor strumienia.

4

Możesz odczytywać bajty, które chcesz, do łańcucha znaków lub tablicy znaków, możesz użyć tego łańcucha za pomocą istringstream i użyć go zamiast swojego strumienia ifstream. Przykład:

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'; 

Jeśli trzeba obsłużyć pliki binarne, można to zrobić za:

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)); 
+0

Należy zauważyć, że to rozwiązanie będzie działać tylko z plikami tekstowymi. –

+2

@KhaledNassar: Można go łatwo dostosować do pracy z plikami binarnymi. Gotowe. –

+0

Jednym z problemów związanych z tym podejściem jest to, że wartość do przeczytania może być dość duża. Pewnie, czy rzeczywiście jest to ogromne, możesz mimo wszystko zająć się zasięgiem oddzielnie. –

2

Możesz chcieć zaimplementować własną klasę czytnika strumień (najlepiej poprzez jakiś interfejs ifstream jeśli taki istnieje) .

Powiązane problemy