2012-08-01 77 views
9

Tôi cố gắng để đọc từ một tập tin mà đang phát triển (một cái gì đó tương tự như những gì tail -F làm), nhưng phải có một số vấn đề với mã của tôi:Cách đọc tệp văn bản đang phát triển trong C++?

string log, logFile("test.log"); 
size_t p = 0; 

while(true) 
{ 
    ifstream ifs(logFile.c_str()); 

    ifs.seekg(p); //*1 

    while(ifs.eof() == false) 
    { 
     getline(ifs, log); 

     cout << log << endl; 

     p = ifs.tellg(); //*2 
    } 

    nanosleep(&pause, NULL); 
} 

Nếu không có dòng // * 1 và // * 2, tệp nhật ký được đọc chính xác đến cuối của nó, nhưng nếu dòng mới được thêm vào không có gì xảy ra.

Với seekg và tellg tôi đang cố gắng lưu trữ vị trí kết thúc hiện tại của tệp, để khi tôi mở lại, tôi có thể đi tới đó và đọc những gì đã được thêm vào.

Tôi muốn biết điều gì sai trong mã của mình và nếu thực sự cần thiết phải đóng và mở lại cùng một tệp cho mục đích này.

Cảm ơn bạn.

Trả lời

12

Vòng lặp là không chính xác như khi eof() được gặp tellg() lợi nhuận -1 và không có kiểm tra cho eof() ngay sau khi cuộc gọi đến getline() mà cần phải có. Thay đổi vòng lặp để:

while (getline(ifs, log)) 
{ 
    cout << log << endl; 
    p = ifs.tellg(); 
} 

Ngoài ra, như p được khai báo là một size_t khi tellg() trở -1 giá trị của p đã được thiết lập để 4294967295. Điều này có nghĩa là seekg() đã được đặt ở ngoài phần cuối của tệp. Thay đổi loại p để std::streamoff và xác nhận cuộc gọi đến seekg() đã thành công:

if (ifs.seekg(p)) 
{ 
    while (getline(ifs, log)) 
    { 
     cout << log << endl; 
     p = ifs.tellg(); 
    } 
} 

nếu nó thực sự cần thiết để đóng và mở lại tập tin tương tự cho mục đích này.

Không, không cần thiết nhưng bạn cần phải clear() trạng thái eof từ luồng. Sau đây là một thay thế cho một phiên bản chỉnh sửa của mã đăng:

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

int main() 
{ 
    std::ifstream ifs("test.log"); 

    if (ifs.is_open()) 
    { 
     std::string line; 
     while (true) 
     { 
      while (std::getline(ifs, line)) std::cout << line << "\n"; 
      if (!ifs.eof()) break; // Ensure end of read was EOF. 
      ifs.clear(); 

      // You may want a sleep in here to avoid 
      // being a CPU hog. 
     } 
    } 

    return 0; 
} 
+0

Bây giờ nó đang hoạt động đúng cách. Cảm ơn bạn. – Pietro

+0

Tôi nhận thấy rằng nếu tôi tạo đối tượng ifstream vào vòng lặp nó hoạt động, nhưng nếu tôi tạo nó bên ngoài nó thì không. Có cần phải đóng và mở lại một tệp để đọc những gì đã được thêm vào nó không? – Pietro

+0

@Pietro, bạn cần xóa trạng thái eof của 'ifstream' bằng cách gọi' ifs.clear() 'trước lần thử đọc tiếp theo. Tôi _think_ 'tellg()' và 'seekg()' sẽ không cần thiết với cách tiếp cận này. – hmjd

1

Phương pháp này đã làm việc một cách trung thực đối với tôi:

#include <string> 
#include <chrono> 
#include <thread> 
#include <fstream> 
#include <iostream> 

int main(int, char* argv[]) 
{ 
    // open file passed in on command line (at end of file) 
    std::ifstream ifs(argv[1], std::ios::ate); 

    if(!ifs.is_open()) 
    { 
     std::cerr << "ERROR: opening log file: " << argv[1] << '\n'; 
     return 1; 
    } 

    // remember file position 
    std::ios::streampos gpos = ifs.tellg(); 

    std::string line; 
    bool done = false; 

    while(!done) 
    { 
     // try to read line 
     if(!std::getline(ifs, line) || ifs.eof()) 
     { 
      // if we fail, clear stream, return to beginning of line 
      ifs.clear(); 
      ifs.seekg(gpos); 

      // and wait to try again 
      std::this_thread::sleep_for(std::chrono::milliseconds(100)); 
      continue; 
     } 

     // remember the position of the next line in case 
     // the next read fails 
     gpos = ifs.tellg(); 

     // process line here 
     std::cout << "line: " << line << std::endl; 
    } 
} 
0

Mã này làm việc cho tôi:

struct timespec pause; 
pause.tv_sec = 1; 
pause.tv_nsec = 0; 

std::ifstream ifs("test.log"); 
std::streamoff p; 

if(ifs.is_open()) 
{ 
    std::string line; 

    while(true) 
    { 
     if(ifs.seekg(p)) 
     { 
      while(std::getline(ifs, line)) 
      { 
       std::cout << line << std::endl; 
       p = ifs.tellg(); 
      } 
     } 

     ifs.clear(); 

     nanosleep(&pause, NULL); 
    } 
} 
Các vấn đề liên quan