質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.49%

  • Go

    511questions

    Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

[Go(golang)] ファイル末尾から1行ずつ読み込みたい

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,135

nyankodon

score 43

Go言語でログファイルなど、ファイル末尾から1行読み込んで順次処理を行いたいのですが、これは自前で実装するしかないのでしょうか?

もし簡単な方法がありましたら教えて下さい。宜しくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

0

単純に行単位で読み切って逆順で表示するだけです。

package main

import (
    "bufio"
    "fmt"
    "log"
    "os"
)

func main() {
    fp, err := os.Open("log.txt")
    if err != nil {
        log.Fatalln(err)
    }
    defer fp.Close()
    scanner := bufio.NewScanner(fp)
    lines := []string{}
    for scanner.Scan() {
        lines = append(lines, scanner.Text())
    }
    for i := range lines {
        fmt.Println(lines[len(lines)-i-1])
    }
}

ただこれを巨大なログファイルなどに適用するとメモリが大変なことになります。

  • fp.Stat()でえられるファイルサイズ分
  • io.Seekableなfp.Seekでシークしながら
  • ファイルを読みつつ改行を探す
package main

import (
    "fmt"
    "io"
    "log"
    "os"
)

func main() {
    fp, err := os.Open("log.txt")
    if err != nil {
        log.Fatalln(err)
    }
    defer fp.Close()
    info, err := fp.Stat()
    if err != nil {
        log.Fatalln(err)
    }
    pos := info.Size()
    line := ""
    for pos > 0 {
        b := []byte{0}
        _, err := fp.Seek(pos-1, os.SEEK_SET)
        if err != nil {
            log.Fatalln(err)
        }
        sz, err := fp.Read(b)
        if err != nil {
            if err != io.EOF {
                log.Fatalln(err)
            }
        }
        if sz > 0 {
            if b[0] == '\n' {
                if len(line) > 0 {
                    fmt.Println(line)
                    line = ""
                }
            } else {
                line = string(b) + line
            }
            pos--
        }
    }
    if len(line) > 0 {
        fmt.Println(line)
    }
}

しかし、この方法もシステムコールの発行回数が多く、
巨大なファイルの場合に効率がよくありません。
チャンク(かたまり)サイズ毎に逆順に読んで、
チャンクごとにうまく改行単位の切り出しをすると良いでしょう。
参考実装はtacというLinuxのコマンドラインツールを参考に。
(もしくはtacコマンドを子プロセスとして呼ぶ手もあります)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/28 09:49

    ちなみにtacは8KBセグメントを1チャンクとして扱うみたい。

    キャンセル

  • 2018/05/29 17:11

    思ったより結構手間がかかるものなんですね。
    回答有り難うございます。参考にさせて頂きます。

    キャンセル

  • 2018/05/30 08:18

    システム(OS)が、順読みしか支援してくれないので、、、。この課題はどの言語でもややこしくなります。

    キャンセル

0

このようなことを昔やろうとしていたのですが、OSSにしていなかったので先程OSSにしておきました。
https://github.com/pyama86/ptail

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/29 17:13

    おお、便利そうだ!回答ありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.49%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    File's Ownerとは

    現在Xib関連の操作をしており、色々なサイトでFile's Ownerとクラスをひも付けたりしているのですが、このFile's Ownerとは一体何なのでしょうか? 例えば新たに

  • 受付中

    Mac OS X のターミナル

    terminal.app を使ってファイル操作をする際にデスクトップまで行き、lsコマンドでデスクトップのファイルを表示するとGUIでは見えていない以下の様な形式のファイルが見えま

  • 解決済

    mysql エラー The server quit without updating PID fil...

    以前は使用できていたのですがPCを再起動した際にmysqlのエラーが出るようになってしまいました。 The server quit without updating PID 

  • 解決済

    Google Drive APIsをPythonでいじるための設定をしたい

    前提・実現したいこと Google Drive APIsリンク内容のガイドに沿って進めてstep4のquickstart.pyを実行したところ、以下のエラーメッセージが発生しまし

  • 受付中

    Cyberduckを使って、楽にローカルのファイルと同期する方法

    こんにちは 現在サーバとのFTP通信をCyberduckを介して行っているのですが、現在作成中のコンテンツの編集方法として、 1、ローカルにあるファイルを変更 2、Cyb

  • 解決済

    Xcodeアプリファイルの出力先について(build時)

    Xcodeで開発中のアプリをbuild/runした際に作成される、アプリファイル(ipa)はどこに出力されるのでしょうか? インターネットで調べると、ipaファイルを作成する際に

  • 受付中

    [Swift]ExtAudioFileOpenURL実行時のエラーを解決したい

    背景 SwiftでiPhoneアプリを開発中です。 アプリ内で、m4aからwavへの音声変換を行おうとしています。 以下の記事を参考にしています。 Swift3でCor

  • 解決済

    Use of unresolved identifier 'Init'

    Swift4でFoldingCellというライブラリを使いたいのですが、Githubソースコードをそのままコピーしてもエラーが出てきます。エラーの内容はUse of unresol

同じタグがついた質問を見る

  • Go

    511questions

    Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。