Edited at

Go でファイルを1行ずつ読み込む(csv ファイルも)

More than 1 year has passed since last update.


概要

ファイルを読み込んで処理することがよくあるので忘備用のメモです.


ファイルを1行ずつ読み込む


bufio.Readerで読み込む


ReadString

引数にファイルが指定されていれば,ファイルをオープンして1行ずつ読み込みます.

引数が指定されていなければ,標準入力から1行ずつ読み込みます.


追記:ReadString('\n')で読み込むとWindowsの場合\rが残ってしまうのでReadLineの方がいいとのコメントいただきましたので,ReadLine使った版も載せておきました.


os.EOFでなくてio.EOFなのがはまりどころでした.

Readerはファイルをクローズすれば閉じられるみたいです.

package main

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

func main() {
var fp *os.File
var err error

if len(os.Args) < 2 {
fp = os.Stdin
} else {
fmt.Printf(">> read file: %s\n", os.Args[1])
fp, err = os.Open(os.Args[1])
if err != nil {
panic(err)
}
defer fp.Close()
}

reader := bufio.NewReaderSize(fp, 4096)
for line := ""; err == nil; line, err = reader.ReadString('\n') {
fmt.Print(line)
}
if err != io.EOF {
panic(err)
}
}


ReadLine

コメントいただいたので修正版.

package main

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

func main() {
var fp *os.File
var err error

if len(os.Args) < 2 {
fp = os.Stdin
} else {
fmt.Printf(">> read file: %s\n", os.Args[1])
fp, err = os.Open(os.Args[1])
if err != nil {
panic(err)
}
defer fp.Close()
}

reader := bufio.NewReaderSize(fp, 4096)
for {
line, _, err := reader.ReadLine()
fmt.Println(string(line))
if err == io.EOF {
break
} else if err != nil {
panic(err)
}
}
}


bufio.Scannerで読み込む (推奨)

面倒だなとおもったらbufioにScanner という便利なものがありました.

http://golang.org/pkg/bufio/#example_Scanner_lines

サンプルを参考に,上の例と同じにするとこんな感じでしょうか.

package main

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

func main() {
var fp *os.File
var err error

if len(os.Args) < 2 {
fp = os.Stdin
} else {
fp, err = os.Open(os.Args[1])
if err != nil {
panic(err)
}
defer fp.Close()
}

scanner := bufio.NewScanner(fp)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
panic(err)
}
}


csv(tsv)形式のファイルの読み込み

csv形式のファイルを読み込むReaderが用意されているのでこれを使えば簡単.

区切り文字の指定をReader.Commaに設定するのがなんか気持ち悪いですが・・・.

下記はタブ区切りのファイルを読む場合のサンプルです.

package main

import (
"encoding/csv"
"fmt"
"io"
"os"
)

func main() {

var fp *os.File
if len(os.Args) < 2 {
fp = os.Stdin
} else {
var err error
fp, err = os.Open(os.Args[1])
if err != nil {
panic(err)
}
defer fp.Close()
}

reader := csv.NewReader(fp)
reader.Comma = '\t'
reader.LazyQuotes = true // ダブルクオートを厳密にチェックしない!
for {
record, err := reader.Read()
if err == io.EOF {
break
} else if err != nil {
panic(err)
}
fmt.Println(record)
}
}