「tail-f」と同じ機能を持つ小さなコードを C++ で作成したいと考えています。テキスト ファイル内の新しい行を監視し、それらを標準出力に表示します。
アイデアは、ファイルを監視するスレッドを持つことです
毎回ファイルを開いたり閉じたりせずに簡単に行う方法はありますか?
ファイルを読み続けるだけです。読み取りに失敗した場合は、何もしません。開閉を繰り返す必要はありません。ただし、オペレーティング システム固有の機能を使用してファイルを監視する方がはるかに効率的であることがわかります (OS が提供している場合)。
Linux ではinotifyを、Mac OS では kqueue を見てください。
Inotifyは Linux カーネル サブシステムであり、ファイルのイベントをサブスクライブできるようにし、ファイルでイベントが発生したときにアプリケーションに報告します。
以下のコードが getc の代わりに getline を使用し、新しい行をスキップしないことを除いて、https: //stackoverflow.com/a/7514051/44729 と同じです。
#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);
}
}
私はこれをPerlのマニュアルの1つで読みましたが、標準のCに簡単に変換でき、次に標準のCに変換できますistream
。
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
フラグを付けてもう一度シークし、ファイルの終わりを更新して、さらにデータを読み取ります。
ingの代わりに、他の回答で提案されているように、ファイルが更新/クローズされるまで正確にスリープ(実際にはエミュレートされたファイルからの読み取り中にブロック)sleep
するためにinotifyを使用できます。ただし、これはLinux固有であり、標準のC++ではありません。
これも実装する必要がありました。標準 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);
}
}