色んな書き込み方があり、何かとごちゃまぜになったので、一旦まとめてみました。
パターンがあり、いつ何を使えば良いか見えてきたので、同じく混乱している方の参考になればと思います。
ざっくりと
こんな感じになる。
-
書き込み先を決める (例: file, buffer)。ファイルの場合
defer Close()
を忘れずに - データを変換する (例: []byte, Marshal), または 書き込むやつを取得する (例: Writer, Encoder)
- 書き込む (例: Write, Encode)
データ格納先へのデータの渡し方が多少違うので、覚えてなければ、都度マニュアルを確認しましょ。
単純に文字列をファイルに書き込む
なんでもいいからファイルに書き込みたいときに使います。
全体の流れ
- 書き込み先のファイル作成 (
f := os.Create
) - バイト文字列に変換 (
d := []byte{"文字列"}
) - 書き込み (
f.Write(d)
)
コード①
package main
import (
"fmt"
"log"
"os"
)
func main() {
// 1. 書き込み先のファイル作成
f, err := os.Create("test.txt")
if err != nil {
log.Fatal(err)
}
defer f.Close()
// 2. バイト文字列に変換
d := []byte("バイト文字列に変換")
// 3. 書き込み
n, err := f.Write(d)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%d bytes 書き込んだよ!", n)
}
コード②: ioutil.WriteFile
を使えばファイル作成ステップ(①)を省略できる
package main
import (
"io/ioutil"
"log"
)
func main() {
// 2. バイト文字列に変換
d := []byte("バイト文字列に変換")
// 3. 書き込み
err := ioutil.WriteFile("test.txt", d, 0644)
if err != nil {
log.Fatal(err)
}
}
ライター (Writer
) を使って書き込む
bufio や CSV で使います。
参考: NewWriter
全体の流れ
-
書き込み先のファイル生成 (
f := os.Create
) -
生成したファイルに書き込む、ライターを取得 (
w := NewWriter(f)
)- パッケージによっては、
defer w.Flush()
を忘れずに (例: bufio & CSV)
- パッケージによっては、
-
書き込み (
w.Write()
)- CSV の場合、引数は
[]string
を渡す。 - Bufio の場合、引数は
[]byte
を渡す。ただWriteString
で[]string
を渡せる
- CSV の場合、引数は
コード
package main
import (
"encoding/csv"
"log"
"os"
)
func main() {
data := [][]string{
{"name", "age"},
{"田中", "25"},
{"加藤", "30"},
}
// 1. 書き込み先のファイル生成
f, err := os.Create("test.csv")
if err != nil {
log.Fatalln("failed to open file", err)
}
defer f.Close()
// 2. ライターを取得
w := csv.NewWriter(f)
defer w.Flush()
// 3. 書き込み
for _, record := range data {
err := w.Write(record)
if err != nil {
log.Fatal(err)
}
}
}
Encoder を使って書き込む
JSON や XML で使います。
参考: NewEncoder
全体の流れ
-
書き込み先のファイル生成 (
f := os.Create("test.json")
) -
ファイルに書き込む、エンコーダを取得 (
encoder := json.newEncoder(f)
) -
構造体を JSON データにエンコードする (
encoder.Encode(&data)
)
コード ①
package main
import (
"encoding/json"
"log"
"os"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
data := []User{
User{Name: "田中", Age: 25},
User{Name: "加藤", Age: 30},
}
// 1. 書き込み先のファイル生成
f, err := os.Create("test.json")
if err != nil {
log.Fatal(err)
}
// 2. ファイルに書き込む、エンコーダを取得
encoder := json.NewEncoder(f)
// 3. data をファイルに書き込み
err = encoder.Encode(&data)
if err != nil {
log.Fatal(err)
}
}
コード ②: エンコーダーの取得と書き込み、一連の流れで書ける
package main
import (
"encoding/json"
"log"
"os"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
data := []User{
User{Name: "田中", Age: 25},
User{Name: "加藤", Age: 30},
}
// 1. 書き込み先のファイル生成
f, err := os.Create("test.json")
if err != nil {
log.Fatal(err)
}
// 2. ファイルに書き込む、エンコーダを取得 & 3 書き込み
err = json.NewEncoder(f).Encode(&data)
if err != nil {
log.Fatal(err)
}
}
Marshal を使って書き込む
JSON や XML で使います。
全体の流れ
-
書き込み先のファイル生成 (
f := os.Create("test.json)
) -
構造体を JSON データに変換する (
output, _ := json.Marshal(&data)
) -
データを書き込む (
f.Write(output)
)
コード
import (
"encoding/json"
"fmt"
"log"
"os"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
data := []User{
User{Name: "田中", Age: 25},
User{Name: "加藤", Age: 30},
}
// 1. 書き込み先のファイル生成
f, err := os.Create("test.json")
if err != nil {
log.Fatal(err)
}
// 2. バイト文字列の JSON データに変換
output, err := json.Marshal(&data)
if err != nil {
log.Fatal(err)
}
// 3. data を書き込み
n, err := f.Write(output)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%d bytes 書き込んだよ!", n)
}
番外編: 書き込み先がバッファの場合
もちろん、ファイルだけでなくバッファ (buf := new(bytes.Buffer)
) にも書き込めます
package main
import (
"bytes"
"encoding/json"
"fmt"
"log"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
data := []User{
User{Name: "田中", Age: 25},
User{Name: "加藤", Age: 30},
}
// 1. 書き込み先のバッファを生成
buf := new(bytes.Buffer)
// 2. バッファに書き込む、エンコーダを取得
encoder := json.NewEncoder(buf)
// 3. data をバッファに書き込む
err := encoder.Encode(&data)
if err != nil {
log.Fatal(err)
}
}
番外編: Encode vs Marshal どっちを使うべきか?
JSON や XML は共に、Encode と Marshal が使え、同じ結果が得られます。
では違いはなんなのでしょうか?
Stack Overflow( 参考: in Golang, what is the difference between json encoding and marshalling ) によると、違いはこのようです。
- Marshal => String
- Encode => Stream
使い分けとして、文字列やバイト文字としてして扱いたい場合は Marshal、それ以外では Encode を使うようです。
また、GitHub の Q&A でも、
- (メモリ上の) バイト文字列を取り扱う場合は、Marshal
- Reader/Writer (ファイルなどの stream) を取り扱う場合は、Encode
と回答されてますね。