2010-04-23 88 views
14

我想用C++創建一個與「tail -f」相同功能的小代碼:觀察文本文件中的新行並在標準輸出中顯示它們。在C++中實現「tail -f」

的想法是有一個監視文件

有一個簡單的辦法做到這一點不開,每次關閉文件的主題?

+0

你可能也很難在純C做這++ 。你將不得不使用一些平臺特定的API。 (對於初學者,我不認爲你可以用C++非獨佔地打開一個文件。) – sbi 2010-04-23 07:51:49

+1

@sbi我不認爲C++標準對排他性有什麼要說的。 – 2010-04-23 07:54:08

+1

有沒有理由不能使用tail -f? – 2010-04-23 08:03:00

回答

11

只要繼續閱讀文件。如果讀取失敗,則不執行任何操作。沒有必要反覆打開和關閉它。但是,如果您的操作系統提供這些功能,您將發現使用特定於操作系統的功能來監視文件效率更高。

+2

+1:嘗試閱讀到目前爲止的文件末尾(對於合理長度的文件),每秒一次在實踐中很便宜。你只是閱讀,直到你完成,然後睡一秒,然後再次嘗試閱讀。 (如果你在Windows上,注意用正確的共享標誌打開,這樣你就不會鎖定其他的作者,這可能意味着使用本地IO調用,而不是C++標準的調用...) – 2010-04-23 08:23:34

11

查看Linux上的inotify或Mac OS上的kqueue。

Inotify是Linux內核子系統,允許您訂閱文件上的事件,並在文件發生偶發事件時向您的應用程序報告。

+0

Windows有一個等價的API用於在文件更改時發送通知。 – 2010-04-23 17:49:54

1

我在one of Perl manuals中讀到這個,但它很容易翻譯成標準C,而標準C又可以翻譯成istream s。

seek FILEHANDLE,POSITION,WHENCE 
     Sets FILEHANDLE's position, just like the "fseek" call of 
     "stdio". 
     <...> 
     A WHENCE of 1 ("SEEK_CUR") is useful for not moving the file 
     position: 

      seek(TEST,0,1); 

     This is also useful for applications emulating "tail -f". Once 
     you hit EOF on your read, and then sleep for a while, you might 
     have to stick in a seek() to reset things. The "seek" doesn't 
     change the current position, but it does clear the end-of-file 
     condition on the handle, so that the next "<FILE>" makes Perl 
     try again to read something. We hope. 

至於我記得,fseek被稱爲iostream::seekg。所以你應該基本上做同樣的事情:尋找文件的結尾,然後睡覺並用ios_base::cur標誌再次尋找以更新文件結束並讀取更多數據。

代替sleep ING,你可以(在從一個模擬的文件讀取,實際上是塊)正是使用的inotify,如the other answer建議,睡覺,直到該文件被更新/關閉。但這是Linux特有的,並不是標準的C++。

+0

熱愛「我們希望」關門。「這很奇怪,但它很好,因爲它很奇怪」以及很多其他自我炫耀的實現,它們都是perl的典型代表... – 2010-04-23 09:17:37

+0

@Stefano - 嗯,這裏很好,因爲它涉及到Perl的linewise實現文件閱讀(''),而不是關於'fseek'如何工作。我希望。 – 2010-04-23 09:20:06

1

我也需要實現這一點,我只是寫了一個標準C++的快速入門。黑客在文件中搜索最後一個0x0A(換行字符),並在最後一個換行值變爲較大值時輸出該換行之後的所有數據。該代碼是在這裏:

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

using namespace std; 


int find_last_linefeed(ifstream &infile) { 

    infile.seekg(0,ios::end); 
    int filesize = infile.tellg(); 

    for(int n=1;n<filesize;n++) { 
    infile.seekg(filesize-n-1,ios::beg); 

    char c; 
    infile.get(c); 

    if(c == 0x0A) return infile.tellg(); 
    } 
} 


int main() { 


    int last_position=-1; 
    for(;;) { 

    ifstream infile("testfile"); 
    int position = find_last_linefeed(infile); 

    if(position > last_position) { 
     infile.seekg(position,ios::beg); 
     string in; 
     infile >> in; 
     cout << in << endl; 
    } 
    last_position=position; 

    sleep(1); 
    } 

} 
2

相同https://stackoverflow.com/a/7514051/44729除了下面的代碼使用,而不是GETC函數getline,而不是跳過新線

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

using namespace std; 

static int last_position=0; 
// read file untill new line 
// save position 

int find_new_text(ifstream &infile) { 

    infile.seekg(0,ios::end); 
    int filesize = infile.tellg(); 

    // check if the new file started 
    if(filesize < last_position){ 
     last_position=0; 
    } 
    // read file from last position untill new line is found 

    for(int n=last_position;n<filesize;n++) { 

     infile.seekg(last_position,ios::beg); 
     char test[256]; 
     infile.getline(test, 256); 
     last_position = infile.tellg(); 
     cout << "Char: " << test <<"Last position " << last_position<< endl; 
     // end of file 
     if(filesize == last_position){ 
     return filesize; 
     } 

    } 

    return 0; 
} 


int main() { 

    for(;;) { 
    std::ifstream infile("filename"); 
    int current_position = find_new_text(infile); 
    sleep(1); 
    } 

} 
+0

文件大小 Angela 2014-11-06 01:01:55