4

When I try to save the map of type map[mapKey]string into a file using gob encoder, it is not saving string in file.

Here mapKey is struct and map value is long json string.

type mapKey struct{
    Id1 string
    Id2 string
}

And whenever I am use nested map instead of the struct like:

var m = make(map[string]map[string]string)

It is working fine and saving string properly. I am not sure what I am missing here.

Code to encode, decode and save it in file:

func Save(path string, object interface{}) error {
    file, err := os.Create(path)
    if err == nil {
        encoder := gob.NewEncoder(file)
        encoder.Encode(object)
    }
    file.Close()
    return err
}

// Decode Gob file
func Load(path string, object interface{}) error {
    file, err := os.Open(path)
    if err == nil {
        decoder := gob.NewDecoder(file)
        err = decoder.Decode(object)
    }
    file.Close()
    return err
}

func Check(e error) {
    if e != nil {
        _, file, line, _ := runtime.Caller(1)
        fmt.Println(line, "\t", file, "\n", e)
        os.Exit(1)
    }
}
4

1 回答 1

5

There is nothing special in encoding a value of type map[mapKey]string.

See this very simple working example which uses the specified reader/writer:

func save(w io.Writer, i interface{}) error {
    return gob.NewEncoder(w).Encode(i)

}
func load(r io.Reader, i interface{}) error {
    return gob.NewDecoder(r).Decode(i)
}

Testing it with an in-memory buffer (bytes.Buffer):

m := map[mapKey]string{
    {"1", "2"}: "12",
    {"3", "4"}: "34",
}
fmt.Println(m)

buf := &bytes.Buffer{}
if err := save(buf, m); err != nil {
    panic(err)
}

var m2 map[mapKey]string
if err := load(buf, &m2); err != nil {
    panic(err)
}
fmt.Println(m2)

Output as expected (try it on the Go Playground):

map[{1 2}:12 {3 4}:34]
map[{1 2}:12 {3 4}:34]

You have a working code, but know that you have to call Load() with a pointer value (else Decoder.Decode() wouldn't be able to modify its value).

Also a few things to improve it:

  • In your example you are swallowing the error returned by Encoder.Encode() (check it and you'll see what the problem is; a common problem is using a struct mapKey with no exported fields in which case an error of gob: type main.mapKey has no exported fields would be returned).
  • Also you should call File.Close() as a deferred function.
  • Also if opening the file fails, you should return early and you shouldn't close the file.

This is the corrected version of your code:

func Save(path string, object interface{}) error {
    file, err := os.Create(path)
    if err != nil {
        return err
    }
    defer file.Close()
    return gob.NewEncoder(file).Encode(object)
}

func Load(path string, object interface{}) error {
    file, err := os.Open(path)
    if err != nil {
        return err
    }
    defer file.Close()
    return gob.NewDecoder(file).Decode(object)
}

Testing it:

m := map[mapKey]string{
    {"1", "2"}: "12",
    {"3", "4"}: "34",
}
fmt.Println(m)

if err := Save("testfile", m); err != nil {
    panic(err)
}

var m2 map[mapKey]string
if err := Load("testfile", &m2); err != nil {
    panic(err)
}
fmt.Println(m2)

Output as expected:

map[{1 2}:12 {3 4}:34]
map[{1 2}:12 {3 4}:34]
于 2016-07-05T13:56:08.490 回答