2012-05-30 29 views
11

Có cách nào để đọc một tập tin ngược, từng dòng một, mà không cần phải đi qua các tập tin từ đầu để bắt đầu đọc ngược?Đọc một tệp ngược?

+2

Bạn có thể đọc các dòng của tệp thành 'vectơ' và ngược lại. – hmjd

+0

@hmjd Đây phải là câu trả lời, IMO. – jrok

Trả lời

8

Theo nhận xét, một lựa chọn có thể (khá đơn giản) sẽ được đọc các dòng vào một vector.Ví dụ:

#include <iostream> 
#include <fstream> 
#include <string> 
#include <vector> 

int main() 
{ 
    std::ifstream in("main.cpp"); 

    if (in.is_open()) 
    { 
     std::vector<std::string> lines_in_reverse; 
     std::string line; 
     while (std::getline(in, line)) 
     { 
      // Store the lines in reverse order. 
      lines_in_reverse.insert(lines_in_reverse.begin(), line); 
     } 
    } 
} 

EDIT:

Theo jrok 's và Loki Astari' s ý kiến, push_back() sẽ hiệu quả hơn nhưng các dòng sẽ được theo thứ tự tập tin, lặp đi lặp lại như vậy ngược lại (reverse_iterator) hoặc std::reverse() sẽ là cần thiết:

std::vector<std::string> lines_in_order; 
    std::string line; 
    while (std::getline(in, line)) 
    { 
     lines_in_order.push_back(line); 
    } 
+3

Bạn có thể sử dụng 'std :: reverse' sau khi đọc xong hoặc chỉ lặp lại với' reverse_iterator'. – jrok

+0

@jrok, mã chèn ở mặt trước của vectơ khi nó đứng, do đó các dòng sẽ được sắp xếp theo thứ tự ngược lại, do đó không có dạng đảo ngược nào được yêu cầu .. Nếu 'push_back' được sử dụng, thì có, sử dụng một dạng ngược lại . – hmjd

+1

Im sẽ đoán rằng di chuyển tìm kiếm vào mặt sau của tập tin và sau đó lặp đi lặp lại chuyển tiếp sẽ tốt hơn hiệu suất khôn ngoan? – mezamorphic

3

Câu trả lời ngắn gọn là không. Tuy nhiên, bạn có thể sử dụng hàm seek() để di chuyển con trỏ đến nơi bạn muốn. Sau đó đọc() một số dữ liệu từ điểm đó. Nếu bạn biết rõ cách quản lý bộ đệm, thì nó sẽ khá nhanh vì bạn có thể đọc và lưu trữ dữ liệu và sau đó tìm kiếm (các) ký tự dòng mới trước đó. Hãy vui vẻ với \ r \ n mà sẽ được đảo ngược ...

- Cập nhật: một số xây dựng trên các thuật toán tốt -

Đây không phải là mã hợp lệ, nhưng nó sẽ cho bạn một ý tưởng về những gì tôi đang cố gắng để nói ở đây

tập đọc:

int fpos = in.size() - BUFSIZ; 
char buf[BUFSIZ]; 
in.seek(fpos); 
in.read(buf, BUFSIZ); 
fpos -= BUFSIZ; // repeat until fpos < 0, although think of size % BUFSIZ != 0 
// now buf has characters... reset buffer position 
int bpos = BUFSIZ - 1; 

Bắt chuỗi:

// first time you need to call the read 
if(bpos == -1) do_a_read(); 
// getting string 
std::string s; 
while(bpos >= 0 && buf[bpos] != '\n') { 
    s.insert(0, 1, buf[bpos]); 
    --bpos; 
} 
// if bpos == -1 and buf[0] != '\n' then you need to read another BUFSIZ chars 
// and repeat the previous loop... 

// before leaving, skip all '\n' 
while(bpos >= 0 && buf[bpos] == '\n') { 
    --bpos; 
} 
return s; 

Để dễ dàng với '\ r', bạn có thể có thẻ đầu tiên biến tất cả '\ r' thành '\ n'. Nếu không, tất cả các thử nghiệm của '\ n' cũng cần phải kiểm tra cho '\ r'.

+0

Bạn có thể giải thích chi tiết về điểm đệm không? – mezamorphic

+0

@ user1107474: "từng dòng" chỉ là vấn đề diễn giải các byte \ n \ n' thành dòng mới. Nếu bạn đọc ngược byte, và giải thích các byte dòng mới cho mình, bạn chắc chắn có thể đọc dòng ngược. Nó không chỉ là chức năng tiêu chuẩn. – MSalters

+0

Một lưu ý nhỏ ở đây ... s.insert (0, 1, char) là SLOW. Nếu bạn muốn tăng tốc, bạn sẽ muốn lưu điểm kết thúc (bpos trước khi vào trong khi đó) và điểm bắt đầu (bpos sau một khoảng thời gian) và thêm chuỗi đó vào kết quả cùng một lúc. –

5
  1. Mở tệp để đọc, gọi fseek() để tìm cách kết thúc của tập tin, sau đó gọi ftell() để có được độ dài của tập tin. Ngoài ra, bạn có thể nhận được độ dài tệp bằng cách gọi số stat() hoặc fstat()

  2. Phân bổ con trỏ đệm đến kích thước tệp thu được ở # 1, ở trên.

  3. Đọc toàn bộ tệp vào bộ đệm đó - bạn có thể sử dụng fread() để đọc toàn bộ tệp trong một lần phát (giả sử tệp đủ nhỏ).

  4. Sử dụng một con trỏ char khác để truyền tệp từ đầu đến đầu bộ đệm.

+1

Giả sử các tập tin có thể dễ dàng phù hợp với bộ nhớ, đây là một giải pháp tốt, dễ dàng. –

11

Sử dụng memory-mapped file và quay lại. Hệ điều hành sẽ trang trong các phần cần thiết của tập tin theo thứ tự ngược lại.

+0

Đó cũng là một ý tưởng, mặc dù thường xuyên ánh xạ một tệp không chính xác về phía trước (Đặc biệt là lần đầu tiên!) –

2

Hơi phiên bản cải tiến sẽ là thế này: -
1) Tìm cách cuối cùng-1 vị trí
2) Nhận vị trí cuối cùng 1
3) Đọc char và in nó;
4) tìm kiếm 2 pos trở lại;
5) lặp lại 3 & 4 cho last-1 lần;

ifstream in; 
    in.open("file.txt"); 
    char ch; 
    int pos; 
    in.seekg(-1,ios::end); 
    pos=in.tellg(); 
    for(int i=0;i<pos;i++) 
    { 
     ch=in.get(); 
     cout<<ch; 
     in.seekg(-2,ios::cur); 
    } 
    in.close(); 
Các vấn đề liên quan