done is better than perfect

自分が学んだことや、作成したプログラムの記事を書きます。すべての記載は他に定める場合を除き個人的なものです。

Go言語のencoding/gobは1GBまでのファイルしか読み込めない

結構悩んだのでメモ。あるmapsliceなど、何かしらのデータの入った変数をファイルとして書き出して、後で利用したいことがたまにあります。

Pythonならpickleなどを使いますが、Go言語ではencoding/gobという標準ライブラリを使うと似たようなことができるみたいです。

例えば、以下のように書くとmapをファイルとして保存し、後で読み出せます。

package main

import (
    "encoding/gob"
    "log"
    "os"
)

func main() {
    testmap := map[int]int{
        1: 10,
        2: 20,
        3: 30,
    }
    encodeFile, err := os.Create("test.gob")
    if err != nil {
        log.Fatal(err)
    }
    defer encodeFile.Close()
    encoder := gob.NewEncoder(encodeFile)
    if err := encoder.Encode(testmap); err != nil {
        log.Fatal(err)
    }
    log.Println("Done!")
    // Decode start
    newMap := make(map[int]int)
    decodeFile, err := os.Open("test.gob")
    if err != nil {
        log.Fatal(err)
    }
    defer decodeFile.Close()
    decoder := gob.NewDecoder(decodeFile)
    if err := decoder.Decode(&newMap); err != nil {
        log.Fatal(err)
    }
    log.Println(newMap) // Will print like this: map[3:30 1:10 2:20]
}

それはいいのですが、上のコードで言うtestmapが巨大になると、ファイル生成はされるのですがdecodeinvalid message lengthというエラーが出てうまいこと動きません。(自分の環境では、11000*11000の行列を入れたら動きませんでした。)

最終的に、encoding/gobソースコードを読むことで解決しました。

https://golang.org/src/pkg/encoding/gob/decoder.go

ブログにBSDライセンスの条項どうやって載せるのかわからなかったのでソースコードは載せませんが、要するにオーバーフローしないように読み込むファイルのサイズを1GBに制限するよ!といった内容がコメントで書かれています。

なぜファイル生成はできて読み込みはできないのか(´・ω・`)

中のTODOコメントでlimitのコントロールについての言及もあるのですが、今の所Go言語上から制限を外すことはできなさそうです…もしできるのであれば知りたい。あるいは他のもっといい方法があるのでしょうか。


以前も紹介したMarxicoが想像以上に使えますね。ソースコードの整形までやってくれるとは思いませんでした。