はじめて go 言語を使ってみた

プログラミング言語はそれぞれに特徴があって、得意、不得意な部分が、それぞれあると思います。

そんな中、go 言語には以前から興味がありましたが、仕事上、なかなか使う機会が回ってきませんでした。

tour of go を一通り読んでいたので、go の仕事も請けられるだろう、と楽観視していたところ、今回、go で作ってもよいということになったので、本腰を入れて勉強することにしました。(緩いなあ・・・)

フォルダ内のファイルの md5 を記録する

私のプログラミング言語の勉強方法としては、簡単なテーマを決めて、それを実装してみるという方法です。

ディスク上に重複したファイルが増えてきて、重複したファイルを削除したいな、と思っていたので、手始めとして、指定したディレクトリのファイルサイズと md5 sum を sqlite3 db に書き込むといったことをやってみようと思いました。

そのコード。

package main

import (
    "fmt"
    "os"
    "time"
    "path/filepath"
    "crypto/md5"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/sqlite"
    "log"
    "io"
    "encoding/hex"
)

type FileInfo struct {
    gorm.Model
    Name string
    Size int64
    ModTime time.Time
    MD5 string
}

func WalkAndRegister(db *gorm.DB) filepath.WalkFunc {
    return func (path string, info os.FileInfo, err error) error {
        fi, err := os.Stat(path)
        if err != nil {
            return err
        }

        if fi.IsDir() {
            return nil
        }

        f, err := os.Open(path)
        if err != nil {
            return err
        }
        defer f.Close()

        h := md5.New()
        if _, err := io.Copy(h, f); err != nil {
            log.Fatal(err)
        }

        db.Create(&FileInfo{Name: path, Size: fi.Size(), ModTime: fi.ModTime(), MD5: hex.EncodeToString(h.Sum(nil))})
        fmt.Printf("%s\n", path)
        return nil
    }
}

func main() {
    dirs := os.Args[1:]
    if len(dirs) == 0 {
        wd, err := os.Getwd()
        if err != nil {
            return
        }
        dirs = append(dirs, wd)
    }
    dbfile := "/tmp/dupcheck.db"
    db, err := gorm.Open("sqlite3", dbfile)
    if err != nil {
        panic("failed to connect database")
    }
    defer db.Close()

    db.AutoMigrate(&FileInfo{})

    for i := range dirs {
        filepath.Walk(dirs[i], WalkAndRegister(db))
    }
}

ビルドと実行


sudo yum install go (mac なら brew install など)
mkdir dupcheck
cd dupcheck
vim dupcheck.go

go build dupcheck.go とすると、なんやかんやエラーが出るので、以下を追加で実行します。

go get -u github.com/jinzhu/gorm
go get github.com/mattn/go-sqlite3

再度、go build dupcheck.go を実行すると、dupcheck という実行ファイルができます。

./dupcheck 適当なディレクトリ

を実行すると /tmp/dupcheck.db ができます。中身を見たければ、sqlite3 /tmp/dupcheck.db を実行して、select * from file_infos; で見ます。

そうなんや、と感心した点

  • github からライブラリを import できる点 — 昔はたくさんライブラリを取ってきて configure しないといけなかった(いつの時代や)のに、相当便利になったなあ
  • ビルドシステムが内蔵されているのか makefile のようなめんどうなものが不要
  • defer で関数から戻った時に処理を実行させられる点 — 組み込みにこんな安全な機能があったら・・・
  • (私のような C 言語で止まっているような者には理解しづらい)関数の外側にある変数を持った関数を返せる点(closure) — filepath.Walk でどうやって db を渡すん?と思った
  • 例外でなく、error を返す方針 — 私のような C 言語で止まっている者には例外よりわかりやすいかも

おわりに

やはり、「コンピュータは習うより慣れろ」(古い・・・) だと思うので、塾に通う前によかったらご参考にしてください。

それと、go 言語のチュートリアルはわかりやすくインターラクティブに作られていると思うので、興味があれば部分的にでも試してみることをおすすめします。

1969年生まれ。大学卒業後から15年以上にわたり、通信、カードリーダ、セキュリティ業界においてソフトウェア開発に従事。その後、2012年5月に当社を設立。電力、交通、車載向けの組み込み系システム、旅行業界向けの WEB システム開発、音声合成システム、消防向けのシステム開発等に参画。
低コストかつシンプルで安定稼働するシステムの実現を目指し、アーキテクチャ設計に取り組んでいます。
会社情報と代表者守屋のプロフィール詳細