こんにちは。KOUKIです。
とあるWeb系企業で、Goエンジニアをやっています。
今日は、Go言語でファイル検索ツールを作成しましょう。
<目次>
シチュエーション
PC内で「README.md」ファイルを探したくなったとします。
そんな時に、役立つツールです。
実装1
早速、実装しましょう。
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 36 37 38 39 40 41 42 43 |
package main import ( "fmt" "io/ioutil" "path/filepath" "strings" "time" ) var matches []string func fileSearch(root string, targetFileName string) { fmt.Println("Searrching in", root) // ディレクトリを読み込み、ディレクトリやファイルを格納する files, _ := ioutil.ReadDir(root) for _, file := range files { // ファイル名をチェック if strings.Contains(file.Name(), targetFileName) { matches = append(matches, filepath.Join(root, file.Name())) } // ディレクトリの場合はfileSearch関数を再実行 if file.IsDir() { fileSearch(filepath.Join(root, file.Name()), targetFileName) } } } func main() { now := time.Now() searchDir := "/Users/hoge/go/" targetFileName := "README.md" fileSearch(searchDir, targetFileName) for _, file := range matches { fmt.Println("Matched", file) } fmt.Printf("It took %d ms\n", time.Since(now).Milliseconds()) } |
「searchDir」に検索したいディレクトリのパスを指定してください。そして、「targetFileName」には検索したいファイル名を指定します。
fileSearch関数の挙動としては、コメントに書いてあるとおりなので割愛させていただきます。
プログラムを実行してみましょう。
1 2 3 4 5 |
go run main.go Matched /Users/hoge/go/src/golang.org/x/tools/internal/lsp/tests/README.md Matched /Users/hoge/go/src/gopkg.in/yaml.v2/README.md .... It took 18207 ms |
OKですね。処理時間も18sとまずまずの結果です。
平行処理
Go言語には、Goroutineという平行処理を簡単に実装できる機能がありますので、それを使ってみましょう。
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
package main import ( "fmt" "io/ioutil" "path/filepath" "strings" "sync" "time" ) var ( matches []string // WaitGroupを設定 waitgroup = sync.WaitGroup{} // Mutexを設定 lock = sync.Mutex{} ) func fileSearch(root string, targetFileName string) { fmt.Println("Searrching in", root) files, _ := ioutil.ReadDir(root) for _, file := range files { if strings.Contains(file.Name(), targetFileName) { // 読み取り競合が発生しないようにロックをかける lock.Lock() matches = append(matches, filepath.Join(root, file.Name())) lock.Unlock() } if file.IsDir() { // WaitGroup関連の設定 waitgroup.Add(1) // goキーワードでgoroutineを起動 go fileSearch(filepath.Join(root, file.Name()), targetFileName) } } // WaitGroup関連の設定 waitgroup.Done() } func main() { now := time.Now() searchDir := "/Users/hoge/go/" targetFileName := "README.md" // WaitGroup関連の設定 waitgroup.Add(1) // goキーワードでgoroutineを起動 go fileSearch(searchDir, targetFileName) // WaitGroup関連の設定 waitgroup.Wait() for _, file := range matches { fmt.Println("Matched", file) } fmt.Printf("It took %d ms\n", time.Since(now).Milliseconds()) } |
追加したところにコメントをしました。
キーワードとしては、
- go ・・・ goroutine起動
- WaitGroup ・・・ goroutine完了制御
- Mutex ・・・変数などのメモリの読み書き制御
ですね。
詳細は、以下の記事を参考にしてください。ここでは、goroutine制御に必要なものという認識でいていただければ幸いです。
それでは、プログラムを実行しましょう。
1 2 3 4 5 |
go run main.go Matched /Users/hoge/go/pkg/mod/github.com/gofiber/fiber/v2@v2.4.0/middleware/proxy/README.md Matched /Users/hoge/go/pkg/mod/github.com/gofiber/fiber/v2@v2.4.0/internal/encoding/json/README.md ... It took 5489 ms |
なんと、1/3以下のスピードで処理が完了しました!
便利ですね^^
これが、goroutineの力です!
おわりに
いかがだったでしょうか。
Go言語ならファイル検索プログラムを一瞬で実装することが可能ですし、goroutineを使えば処理速度の大幅Upも可能です^^
Go言語を勉強してみたくなりましたでしょうか?
ぜひぜひ、学んでみてください!
日本で、もっとGo言語が使われるようになればなと祈っています^^
それでは、また!
コメントを残す
コメントを投稿するにはログインしてください。