因此,我遵循CLRS算法,用Java编写了该持久性BTree。
我使用FileChannel
和ByteBuffer
将树存储在文件中,并在需要时读写节点。
我尝试查看如何在Go中存储这样的BTree,并发现了os.File
,我认为可以将其与Java的FileChannel
相同的方式使用。
但是,我找不到ByteBuffer
的等效项。我查看了bytes.Buffer
,我看到了它如何工作,但是它没有ByteBuffer
的方便的putInt
,putDouble
等。
我是否必须实现自己的功能才能将整数和 double 转换为字节数组?我还查看了encoding.binary
,但这看起来很麻烦。我知道我必须每次将变量编码为字节数组,然后将该字节数组复制到缓冲区。
在这种情况下,建议使用什么结构?
最佳答案
使用encoding/gob
包
使用 encoding/gob
包,您可以将整个树序列化为一系列字节,并通过单个方法调用将它们反序列化。
请参阅以下示例:
type Node struct {
Data int
Children []*Node
}
func (n *Node) String() string {
buf := &bytes.Buffer{}
buf.WriteString(fmt.Sprintf("Node[Data: %d, Children: [", n.Data))
for i, v := range n.Children {
if i > 0 {
buf.WriteString(", ")
}
buf.WriteString(v.String())
}
buf.WriteString("]")
return buf.String()
}
不需要
Node.String()
方法,我只是创建它来轻松打印/验证树。现在使用
gob
序列化和反序列化树:root := &Node{
Data: 1,
Children: []*Node{
{Data: 2},
{Data: 3},
},
}
fmt.Println(root)
buf := &bytes.Buffer{}
if err := gob.NewEncoder(buf).Encode(root); err != nil {
panic(err)
}
var root2 *Node
if err := gob.NewDecoder(buf).Decode(&root2); err != nil {
panic(err)
}
fmt.Println(root2)
输出(在Go Playground上尝试):
Node[Data: 1, Children: [Node[Data: 2, Children: [], Node[Data: 3, Children: []]
Node[Data: 1, Children: [Node[Data: 2, Children: [], Node[Data: 3, Children: []]
在这里,我使用了内存中的缓冲区(
bytes.Buffer
),但是如果要保存到文件或从文件中加载,甚至不需要内存中的缓冲区,则可以直接将 *os.File
值传递给 gob.NewEncoder()
和 gob.NewDecoder()
(as *os.File
同时实现 io.Reader
和 io.Writer
)。手动序列化/反序列化
还要注意,如果您不想(或不能)一步一步地使用
encoding/gob
进行完整的序列化,则还可以使用 binary.Write()
和 binary.Read()
函数直接写入文件或从文件中读取,而无需使用任何内存缓冲区。请参见以下示例,对
int32
和float64
值进行编码和解码:var i int32
var f float64
i, f = 1, 3.14
buf := &bytes.Buffer{}
if err := binary.Write(buf, binary.LittleEndian, i); err != nil {
panic(err)
}
if err := binary.Write(buf, binary.LittleEndian, f); err != nil {
panic(err)
}
var i2 int32
var f2 float64
if err := binary.Read(buf, binary.LittleEndian, &i2); err != nil {
panic(err)
}
if err := binary.Read(buf, binary.LittleEndian, &f2); err != nil {
panic(err)
}
fmt.Println(i2, f2)
输出(在Go Playground上尝试):
1 3.14
同样,您可以将文件直接传递给
binary.Read()
和binary.Write()
而不是*bytes.Buffer
。非二进制序列化
您还可以使用其他非二进制序列化格式,例如JSON。
encoding/json
包也将能够通过一次调用对整个树进行序列化/反序列化。尽管在存储和速度方面使用JSON的性能较差,但是序列化的格式将更加人性化(更易于读取/编辑),并且与其他应用程序/技术兼容。