【问题标题】:Storing struct trees on disk在磁盘上存储结构树
【发布时间】:2018-10-02 21:37:28
【问题描述】:

我有以下结构:

type Post struct {
  Id    int
  Name  string
  Text  string
  Posts []Post
}

要添加一些数据,我执行以下操作:

var posts []Post

posts = append(posts, Post{Id: 0, Name: "a", Text: "b"})
posts[0].Posts = append(posts[0].Posts, Post{Id: 1, Name: "c", Text: "d"})

posts = append(posts, Post{Id: 2, Name: "e", Text: "f"})
posts[0].Posts = append(posts[0].Posts, Post{Id: 3, Name: "h", Text: "d"})

如何有效地将这个结构树存储在磁盘上?我正在寻找可以在没有服务器的情况下使用的东西(比如 SQLite)。我希望能够搜索Id 2 或3,分别返回带有Id 2 或3 的整个结构。另外,我希望能够更新单个结构 f.e. Id 2.

另外,用Id作为地图的key,使用地图会更好吗?

【问题讨论】:

  • 推荐的解决方案可能取决于问题中未提及的因素,例如您打算存储多少个这些结构,是否可以将它们读入内存,字符串长度和树的深度是否有任何限制?
  • @icza 这些因素与我的用例并不真正相关,但我想要一个能够存储 10 个但也能存储 100k 个结构的有效解决方案。字符串可以是有限的(1024 个字符),但它应该是可配置的。这同样适用于树的深度,在我的用例中,最大深度为 10 就是一个很好的例子。
  • @icza 经过一些思考后,我注意到看看根据这些因素存在哪些类型的不同解决方案会很有趣。
  • 好吧,当您需要一个没有数据库服务器的数据库时,SQLite 是一个不错的选择。这可能是对一组记录进行原子更新的最简单方法。如果您想避免手动编写 SQL,也可以使用 Gorm 关系管理器。

标签: go struct


【解决方案1】:

使用 encoding/gob 将二进制数据放入文件中或再次取出

import (
    "bufio"
    "encoding/gob"
    "fmt"
    "os"
)

type Post struct {
    Id    int
    Name  string
    Text  string
    Posts []Post
}

func main() {

    var posts []Post

    posts = append(posts, Post{Id: 0, Name: "a", Text: "b"})
    posts[0].Posts = append(posts[0].Posts, Post{Id: 1, Name: "c", Text: "d"})

    posts = append(posts, Post{Id: 2, Name: "e", Text: "f"})
    posts[0].Posts = append(posts[0].Posts, Post{Id: 3, Name: "h", Text: "d"})
    fmt.Printf("%v\n", posts)

    path := "post.gob"

    // write
    out, err1 := os.Create(path)
    if err1 != nil {
        fmt.Printf("File write error: %v\n", err1)
        os.Exit(1)
    }
    w := bufio.NewWriter(out)
    enc := gob.NewEncoder(w)
    enc.Encode(posts)
    w.Flush()
    out.Close()

    // read
    b := make([]Post, 10)
    in, err2 := os.Open(path)
    if err2 != nil {
        fmt.Printf("File read error: %v\n", err2)
        os.Exit(1)
    }
    r := bufio.NewReader(in)
    dec := gob.NewDecoder(r)
    dec.Decode(&b)

    fmt.Printf("%v\n", b)

}

【讨论】:

  • 感谢您的回答。不幸的是,这样我将只能获取/更新posts 的全部内容,而不是能够获取/更新单个结构。
  • 您可以更新单个结构。但是您必须将它们全部加载,更新然后重新编写它们。如果(例如)您将每个 Post 结构放在一个文件中,那么更新可能会更快一些,但读取会更慢。有中途的房子,比如使用分片(将 Post 结构列表分成两半或四分之一)。然而,所有这些听起来都像是在重新发明数据库。为什么不尝试用 10 万条记录对上述方法进行计时,看看效果如何?
  • 我肯定要对此做一个基准测试。我只是有点惊讶没有那个用例的库。但我想将结构树存储在磁盘上很常见。
猜你喜欢
  • 2017-03-30
  • 2015-09-09
  • 2012-05-13
  • 1970-01-01
  • 2011-06-08
  • 2012-08-02
  • 1970-01-01
  • 1970-01-01
  • 2016-12-04
相关资源
最近更新 更多