たそらぼ

日頃思ったこととかメモとか。

Scanner構造体を使ったファイルの読み出し

Goのファイル入力に興味があったので、Scanner構造体を使ってファイルの読み込みを試した。
とりあえずCSVを読み出してみて、そのまま(特にCSVっぽい処理もせず、)標準出力してみる。

手順

まずos.Open()で既存のファイルからos.File構造体を作る。
os.Fileはio.Readerの実装なので、Scanner構造体を使って読み出すことができる。
Scanner構造体はfileを読み出すのに用意されたI/Fで、bufio.Reader構造体を使うよりシンプルに実装できる。

コード

package main

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

func main() {

	file, err := os.Open("KEN_ALL_ROME.CSV")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	sc := bufio.NewScanner(file)

	for sc.Scan() {
		fmt.Printf("%v\n", sc.Text())
	}

	if err := sc.Err(); err != nil {
		fmt.Printf("Scanner error: %q\n", err)
	}

}

困った点

・Scan()はエラーが起きたときは後からScanner.Err()で確かめる必要がある。
・bufferのサイズは64*1024であるため、1行がこれより大きいとこれ以降が無視されてしまう。
 事前に1行が64*1024文字より大きいことが分かっている場合は、Scanner.buffer()で最大の値を大きくしておくとよい。
・今回は標準出力するだけでよいが、配列などに格納する際にどうするか分からなかった。
 Goでは取りたい配列長が分かっているならmakeを使って動的に配列を取れるが、Scannerにはサイズを確かめる関数が見当たらなかったのでこれができない。

参考

・サンプルデータ
サンプルデータは何でもいいが、日本郵便のKEN_ALL_ROMEを使った。
そのままだと非常に大きいので、最初の方の行だけ取ってくるとよい。

www.post.japanpost.jp

・makeを使って動的に配列を取る
go-tour-jp.appspot.com