2012-01-22 25 views
6

我可以打開ifstream(或以任何方式設置現有的文件)以僅讀取文件的一部分嗎?例如,我想讓我的ifstream從字節10到50讀取一個文件。尋求位置0將是實際位置10,讀取過去的位置40(現實中爲50)將會在EOF等中重現。這是可能的以任何方式?使用iostreams讀取文件的一部分

回答

7

它可以通過實現一個過濾流緩衝區來完成:你將從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_; 
}; 

您可以使用指針來此流緩衝區的一個實例來initialuze的std::istream。如果這是反覆出現的需求,則可能需要創建一個從std::istream派生的類,而不是設置流緩衝區。

4

你可以將你想要的字節讀入字符串或字符數組,然後你可以使用該字符串和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)); 
+0

應該指出的是,這個解決方案只適用於文本文件。 –

+2

@KhaledNassar:它可以很容易地適應二進制文件。完成。 –

+0

這種方法的一個問題是要閱讀的範圍可能相當大。當然,如果它確實是巨大的,那麼無論如何你都可能想要分開處理這個範圍。 –

2

你可能想實現自己的流讀取器類(最好是通過一些ifstream的接口如果存在的話) 。