はじめて go 言語を使ってみた
2018/12/16 - moriya - ~3 Minutes
プログラミング言語はそれぞれに特徴があって、得意、不得意な部分が、それぞれあると思う。
そんな中、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 言語のチュートリアルはわかりやすくインターラクティブに作られていると思うので、興味があれば部分的にでも試してみることをおすすめしたい。