Auto Hot Keyでファイル最終行を高速表示(tailコマンド相当)
公開日
最近始めたAuto Hot Keyを使ったプログラミングを書いていますが、困ったことにファイル末尾を取得する方法が確立されていないという事実を知りました。
今回は、WEB検索で幾つか見た実装方法を参考に、更に改善できているであろう方法を整理してみたのでまとめたいと思います。
Contents
WEBで紹介されていた実装例
Googleで「ahk tail」「ahk last line」などで検索したところ、だいたい次に紹介されている実装例を見つけました。
ファイル全体を読み取り、該当行数を返却する
一番多い実装です。例えばこちらにて紹介。
最も検索にヒットする、とてもシンプルでわかりやすい方法ですが、ファイル全体を読むので間違えてバイナリファイルを指定してしまった場合や、バイナリファイル並みの巨大なテキストファイル、というような場合に処理時間がかかるかと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Tail(k,file) ; Return the last k lines of file { Loop Read, %file% { i := Mod(A_Index,k) L%i% = %A_LoopReadLine% } L := L%i% Loop % k-1 { IfLess i,1, SetEnv i,%k% i-- ; Mod does not work here L := L%i% "`n" L } Return L } |
ファイルポインタを移動させて1文字づつ読み取り
先ほどと同じこちらで紹介。
ファイルポインタの移動は巨大なファイルだと効率が上がるのですが、1文字づつ読んでいるのが惜しくも劣化の要因。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
fileGetLastLines(varFilename,varLines=1) { linecount:=0 file:=FileOpen(varFilename, "r") if (not file) return 0 Loop { file.Seek(0-A_Index, 2) line:=file.Read(1) if ((RegExMatch(line,"`n") or RegExMatch(line,"`r")) and not File.AtEOF) linecount++ } until ((RegExMatch(line,"`n") or RegExMatch(line,"`r")) and not File.AtEOF and linecount=varLines) Loop { output.=file.Readline() } until (File.AtEOF) file.Close() return output } |
ファイルポインタを移動させて全体読み取り
こちらで紹介。
個人的には好みの実装ですが、1行の文字数が重要にも関わらず固定値で持たせないといけない実装であるが故に、実際のファイルとの乖離が大きいと誤動作するようです。
改善版を作ってみた
これまで紹介されていた実装例では欲しい実装が今ひとつのところで引き当てることが出来なかったので、これらを参考に自作してみました。
良いと思ったファイルポインタの移動(seek)を活用し、さらに1度に読み取るサイズを多め(デフォルト512バイト)に確保。
さらに規定行数を検出できない場合にはエラー相当である空文字を返却する動作です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
;fileNameファイルの末尾lastCount行を返却。 ;ファイルからunitバイト単位に解析する。 fileGetLastLines(fileName, lastCount=1, unit=512) { if (not (file := FileOpen(fileName, "r"))) return "" bufLines := "" Loop, %lastCount% { ;ループごとにファイル末尾(2)からunitバイト分を読み取る file.Seek(-unit * A_Index, 2) bufLines := file.Read(unit) . bufLines ;改行文字(`n)を区切りに行数をカウント pos := 1 lineCount := 0 Loop { pos := InStr(bufLines, "`n", false, pos+1) lineCount++ } until (pos == 0) ;読み取った行数がlastCount+1行になったらループ終了 } until (lineCount >= lastCount + 1) file.Close() if(lineCount >= lastCount + 1){ ;読み過ぎた不要分を破棄して返却 Loop % lineCount - lastCount { pos := InStr(bufLines, "`n", false, 1) bufLines := SubStr(bufLines, pos+1) } return bufLines } return "" } lines := fileGetLastLines(A_ScriptName, 2) MsgBox, [%lines%] |
最後の2行が使用方法のサンプルで実行結果はシンプルなメッセージボックスへの記載。
最後に
結局WEB検索したけど欲しいサンプルコードがなかったので自作しましたが、数10行程度だから検索方法が良くなかったのかもしれません。
レスポンシブ広告
関連記事
-
Auto Hot Keyで簡単にGUIフォームアプリを作る
巷でお手軽プログラミングが楽しめると好評のAuto Hot Keyを体験してみま …