首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何逐行读取gob文件

如何逐行读取gob文件
EN

Stack Overflow用户
提问于 2022-10-19 05:17:39
回答 1查看 38关注 0票数 1

我使用Gob序列化将Message (下面定义的结构)存储在文件中。

代码语言:javascript
复制
type Message struct {
    Message string `json:"message"`
    From    string `json:"from"`
}

我成功地将我的Message放在我使用gob序列化的一个片中,然后将这个序列化的片存储在一个文件中。

但是,通过这样做,我需要从文件中加载整个序列化的切片,对其进行解码,追加新的Message,对切片进行编码,并再次将其保存在文件中。这似乎很复杂,对我来说也不是很好的优化。

函数,用于编解码和写/读。

代码语言:javascript
复制
func (m Message) Encode() ([]byte, error) {
    var res bytes.Buffer
    encoder := gob.NewEncoder(&res)
    err := encoder.Encode(m)

    if err != nil {
        return []byte{}, err
    }
    return res.Bytes(), nil
}

func (m Message) Write(path string) error {
    messages, err := Read(path)
    if err != nil {
        return err
    }

    messages = append(messages, m)

    f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
    if err != nil {
        return err
    }
    defer f.Close()

    encoder := gob.NewEncoder(f)
    encoder.Encode(messages)

    return nil
}

func Read(path string) ([]Message, error) {
    f, err := os.OpenFile(path, os.O_RDWR, 0644)
    if err != nil {
        return []Message{}, err
    }
    defer f.Close()

    m := []Message{}
    decoder := gob.NewDecoder(f)

    if err = decoder.Decode(&m); err != nil {
        if err == io.EOF {
            return []Message{}, nil
        }
        return []Message{}, err
    }

    return m, nil
}

一个解决方案是将序列化的Message直接存储在文件中,然后简单地在文件末尾添加新的Message

我是通过使用os.O_APPEND来追加而不是覆盖entiere文件来实现的:

代码语言:javascript
复制
    f, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)

我还做了其他一些基本的更改,比如用消息替换[]消息,等等。

现在,我可以将Message存储在文件中,只需在文件末尾添加新消息,而无需每次重写entiere文件。

但我必须知道如何读取存储在文件中的Message

前面的代码只读取第一条消息,忽略文件的其余部分。

我找到了许多逐行读取文件的解决方案,但似乎没有一种解决方案适用于gob序列化对象。

是否可以逐行读取存储gob序列化对象的文件?还是必须继续使用当前的解决方案,即存储序列化的片?

注意:我发现了这个主题(Retrieving gobs written to file by appending several times),它看起来描述的是相同类型的问题,但它几乎是7年前的,+描述了一些更复杂的问题

EN

回答 1

Stack Overflow用户

发布于 2022-10-19 19:57:38

我把这作为一个“答案”发布,但是我的问题还没有解决,如果你认为这更合适的话,我可以把它移到我的初始帖子中。

我从这里找到的代码(Retrieving gobs written to file by appending several times)开始进行了一些测试,并试图考虑答案。

我编写了两个新函数,用于在文件中写入gob,并从文件中读取给定数量的gob

代码语言:javascript
复制
func write(enc *gob.Encoder, m Message) {
    err := enc.Encode(m)
    if err != nil {
        panic(err)
    }
}

func read(filename string, to_load int) {
    f, err := os.OpenFile(filename, os.O_RDWR, 0644)
    defer f.Close()
    if err != nil {
        panic(err)
    }

    dec := gob.NewDecoder(f)

    for i := 0; i < to_load; i++ {
        var m Message
        err = dec.Decode(&m)
        if err != nil {
            panic(err)
        }
        fmt.Println("loaded struct:", m)
    }
}

我从答案(https://stackoverflow.com/a/36386843/17070383)中“理解”的一点是,如果所有这些gob都是用gob.Encoder的不同实例编写的,那么从同一个文件读取多个gob可能会很复杂。

所以我编写了一个函数来生成和返回一个gob.Encoder

代码语言:javascript
复制
func getEncoder(fileName string) (*gob.Encoder, *os.File) {
    file, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
    if err != nil {
        panic(err)
    }

    return gob.NewEncoder(file), file
}

然后:

代码语言:javascript
复制
func main() {
    enc, f := getEncoder("test.bin")
    defer f.Close()

    m1 := Message{"Bob", "Hello"}
    m2 := Message{"Bob2", "Hello2"}
    m3 := Message{"Bob3", "Hello3"}

    write(enc, m1)
    write(enc, m2)
    write(enc, m3)

    fmt.Println("Read 2 Message from file : ")
    read("test.bin", 2)

    m4 := Message{"Bob4", "Hello4"}

    write(enc, m4)

    fmt.Println()
    fmt.Println("Read 4 Message from file : ")
    read("test.bin", 4)
}

产出:

代码语言:javascript
复制
Read 2 Message from file : 
loaded struct: {Bob Hello}
loaded struct: {Bob2 Hello2}

Read 4 Message from file : 
loaded struct: {Bob Hello}
loaded struct: {Bob2 Hello2}
loaded struct: {Bob3 Hello3}
loaded struct: {Bob4 Hello4}

看起来效果很好。

现在,如果我启动代码,我尝试读取8 gob而不是4 (4由第一次代码执行编写,4由第二次执行编写)

代码语言:javascript
复制
read("test.bin", 8)

我有这样的输出:

代码语言:javascript
复制
Read 2 Message from file : 
loaded struct: {Bob Hello}
loaded struct: {Bob2 Hello2}

Read 4 Message from file : 
loaded struct: {Bob Hello}
loaded struct: {Bob2 Hello2}
loaded struct: {Bob3 Hello3}
loaded struct: {Bob4 Hello4}
panic: gob: duplicate type received

goroutine 1 [running]:
main.read({0x10df092?, 0xc000012018?}, 0x8)
    /{path}/main.go:34 +0x1c8
main.main()
    /{path}/main.go:72 +0x2c5
exit status 2

它读取第一个执行时编写的前4个gob,然后在读取第5个元素时感到恐慌,第二个元素是用一个新实例gob.Encoder编写的。

为了验证这一点,我修改了代码,用第一个gob.Encoder编写了3个gob.Encoder,用另一个编码器编写了最后一个gob,然后尝试读取4gob

代码语言:javascript
复制
func main() {
    enc, f := getEncoder("test.bin")
    defer f.Close()

    m1 := Message{"Bob", "Hello"}
    m2 := Message{"Bob2", "Hello2"}
    m3 := Message{"Bob3", "Hello3"}

    write(enc, m1)
    write(enc, m2)
    write(enc, m3)

    fmt.Println("Read 2 Message from file : ")
    read("test.bin", 2)

    new_enc := gob.NewEncoder(f) // New encoder

    m4 := Message{"Bob4", "Hello4"} 

    write(new_enc, m4)// Write m4 with new encoder

    fmt.Println()
    fmt.Println("Read 4 Message from file : ")
    read("test.bin", 4)
}

注意:我重新设置了文件"test.bin“

产出:

代码语言:javascript
复制
Read 2 Message from file : 
loaded struct: {Bob Hello}
loaded struct: {Bob2 Hello2}

Read 4 Message from file : 
loaded struct: {Bob Hello}
loaded struct: {Bob2 Hello2}
loaded struct: {Bob3 Hello3}
panic: gob: duplicate type received
...

正如我们所看到的,第四个(用第二个编码器写的)不能被读取。

结论:

我无法真正解释为什么它是那样工作的,但是它似乎不可能在文件中直接存储(并读取) gob序列化的结构,每次有新的记录要保存时,都会在文件末尾追加新的gob

我真的是新来的,我很乐意对此有更多的解释

我找到了两块解决方案:

每次应用程序启动时,您都会创建一个新文件,并实例化链接到该文件的新的

  1. ,以便在

中写入gob

  1. 与第一种解决方案相同,但不每次创建新文件,只需加载文件的内容并使用新的gob.Encoder重写同一文件中的内容。然后每次都有一个新的记录,您可以再次使用这个gob.Encoder将您的gob附加到文件中。

这两种解决方案看起来都很“糟糕”,因为这意味着在应用程序的整个执行过程中,必须保持流打开(与文件一起)。我对此并不熟悉,但看来你应该避免.

请用你所有的知识完成我的帖子!

nem0z

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74120213

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档