Go言語でログファイルなど、ファイル末尾から1行読み込んで順次処理を行いたいのですが、これは自前で実装するしかないのでしょうか?
もし簡単な方法がありましたら教えて下さい。宜しくお願いします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答2件
0
このようなことを昔やろうとしていたのですが、OSSにしていなかったので先程OSSにしておきました。
https://github.com/pyama86/ptail
投稿2018/05/28 07:15
総合スコア8
0
ベストアンサー
単純に行単位で読み切って逆順で表示するだけです。
go
1package main 2 3import ( 4 "bufio" 5 "fmt" 6 "log" 7 "os" 8) 9 10func main() { 11 fp, err := os.Open("log.txt") 12 if err != nil { 13 log.Fatalln(err) 14 } 15 defer fp.Close() 16 scanner := bufio.NewScanner(fp) 17 lines := []string{} 18 for scanner.Scan() { 19 lines = append(lines, scanner.Text()) 20 } 21 for i := range lines { 22 fmt.Println(lines[len(lines)-i-1]) 23 } 24}
ただこれを巨大なログファイルなどに適用するとメモリが大変なことになります。
- fp.Stat()でえられるファイルサイズ分
- io.Seekableなfp.Seekでシークしながら
- ファイルを読みつつ改行を探す
go
1package main 2 3import ( 4 "fmt" 5 "io" 6 "log" 7 "os" 8) 9 10func main() { 11 fp, err := os.Open("log.txt") 12 if err != nil { 13 log.Fatalln(err) 14 } 15 defer fp.Close() 16 info, err := fp.Stat() 17 if err != nil { 18 log.Fatalln(err) 19 } 20 pos := info.Size() 21 line := "" 22 for pos > 0 { 23 b := []byte{0} 24 _, err := fp.Seek(pos-1, os.SEEK_SET) 25 if err != nil { 26 log.Fatalln(err) 27 } 28 sz, err := fp.Read(b) 29 if err != nil { 30 if err != io.EOF { 31 log.Fatalln(err) 32 } 33 } 34 if sz > 0 { 35 if b[0] == '\n' { 36 if len(line) > 0 { 37 fmt.Println(line) 38 line = "" 39 } 40 } else { 41 line = string(b) + line 42 } 43 pos-- 44 } 45 } 46 if len(line) > 0 { 47 fmt.Println(line) 48 } 49}
しかし、この方法もシステムコールの発行回数が多く、
巨大なファイルの場合に効率がよくありません。
チャンク(かたまり)サイズ毎に逆順に読んで、
チャンクごとにうまく改行単位の切り出しをすると良いでしょう。
参考実装はtacというLinuxのコマンドラインツールを参考に。
(もしくはtacコマンドを子プロセスとして呼ぶ手もあります)
投稿2018/05/27 21:41
総合スコア3367
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2018/05/29 08:13