問題
Go の Scanner の挙動の違いにより、CSV インポート時のカウントにズレが生じました。
例えば CSV ファイルの中身が「A \n B
」 のように 1 行の中に改行コードを含む場合。
改行コードも含めて 1 行と見なしたいケースを想定します。
下記①の場合ですと、改行コードで分割されて 2 行、
②の場合だと改行コードも含めて 1 行でカウントされます。
今回は②の挙動を期待していたのに、①の処理がなされていたために、想定するカウントとズレが発生した、という問題についてです。
①.bufio.NewScanner
におけるScan
メソッドの挙動
処理
scanner := bufio.NewScanner(csv)
num := 0
for scanner.Scan() {
num++
}
fmt.Println(num)
出力結果
2
説明
公式によると、The split function defaults to ScanLines.
とあります。
そして、The end-of-line marker is one optional carriage return followed by one mandatory newline.
とあります。
つまり、デフォルトでは改行コード(\r?\n
)を見つけると、行末だと判断して 1 行分のデータを返す、ということになります。
補足
bufio
パッケージは、「バッファリング(一時保存機構)付き I/O」を提供してくれます。
参考:https://pkg.go.dev/bufio
②.csv.NewReader
におけるRead
メソッドの挙動
処理
scanner := csv.NewReader(csv)
num := 0
for {
_, err := scanner.Read()
if err == io.EOF { // ファイル終わりに到達した場合は、ループを抜ける
break
} else if err != nil {
return err
}
num++
}
fmt.Println(num)
出力結果
1
説明
上記 csv パッケージの説明に記載されていますが、Carriage returns before newline characters are silently removed.
とあります。
つまり、改行コードで改行されることはなく、改行コードも含めた行末までを 1 行として返す、ということになります。