2012-01-22 32 views
6

Tôi có thể mở ifstream (hoặc đặt một tệp hiện có theo bất kỳ cách nào) để chỉ đọc một phần của tệp không? Ví dụ, tôi muốn có ifstream đọc một tệp từ byte 10 đến 50. Tìm kiếm vị trí 0 sẽ là vị trí 10 trong thực tế, đọc vị trí quá khứ 40 (50 trong thực tế) sẽ lặp lại trong một EOF, v.v. theo bất kỳ cách nào?đọc một phần của tệp bằng iostreams

Trả lời

7

Chắc chắn có thể thực hiện bằng cách triển khai bộ lọc luồng lọc: bạn sẽ lấy được từ std::streambuf và lấy phạm vi bạn muốn hiển thị và bộ đệm luồng cơ bản (tốt, con trỏ đến nó) làm đối số. Sau đó, bạn sẽ tìm đến vị trí bắt đầu. Hàm underflow() bị ghi đè sẽ đọc từ bộ đệm luồng cơ bản vào bộ đệm của nó cho đến khi đã tiêu thụ bao nhiêu ký tự như mong muốn. Dưới đây là một phiên bản hơi thô và hoàn toàn chưa được kiểm tra:

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

Bạn có thể sử dụng một con trỏ đến một thể hiện của bộ đệm dòng này để initialuze một std::istream. Nếu nhu cầu định kỳ này, bạn có thể muốn tạo một lớp có nguồn gốc từ std::istream thiết lập bộ đệm luồng thay thế.

4

Bạn có thể đọc các byte mà bạn muốn vào một chuỗi hoặc mảng char, sau đó bạn có thể sử dụng chuỗi đó với một istringstream, và sử dụng thay vì ifstream của bạn. Ví dụ:

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

Nếu bạn cần để xử lý tập tin nhị phân, bạn có thể làm điều đó quá:

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

Cần lưu ý rằng giải pháp này sẽ chỉ hoạt động với các tệp văn bản. –

+2

@ KhaledNassar: Nó có thể dễ dàng được điều chỉnh để làm việc cho các tệp nhị phân. Làm xong. –

+0

Một vấn đề với cách tiếp cận này là việc chờ đợi được đọc có thể khá lớn. Chắc chắn nếu nó thực sự là to lớn bạn có thể muốn chăm sóc của phạm vi separatly anyway. –

2

Bạn có thể muốn thực hiện riêng lớp đọc luồng của mình (tốt nhất là thông qua một số giao diện ifstream nếu có) .

Các vấn đề liên quan