如何高效地将字节切片插入文件中?

huangapple go评论79阅读模式
英文:

How to efficiently insert a byte slice in a file?

问题

我正在为了好玩而构建一个简单的键值存储。现在,我正在寻找一种有效的方法来在文件中插入一个切片。

我目前的方法是:

  • 找到所需的偏移量

  • 将位于所需插入点之前的块存储在缓冲区中

  • 将字节切片附加到该缓冲区

  • 将文件的剩余部分附加到缓冲区

  • 写入磁盘

问题是:

  • 不一定整个文件都能放入内存中

  • 效率低下

我已经研究了可用的库,不幸的是,我找到的最佳匹配 os.WriteAt 会覆盖后面的块。例如:

import "os"

func main() {
    pathToFile := "./tmp"
    bufferToWrite := []byte{255, 255, 255, 255, 255}

    f, _ := os.OpenFile(pathToFile, os.O_CREATE|os.O_RDWR, os.PermMode)
    defer f.Close()
    f.Write(bufferToWrite)

因此,此时 tmp 的内容将会是(运行 $: xxd -g 1 -b tmp):

11111111 11111111 11111111 (x) 11111111 11111111

让我们尝试在偏移量为 3(x)的位置插入一些内容:

    bufferToInsert := []byte{0, 0}
    f.WriteAt(bufferToInsert, 3)
}

输出将会是:

11111111 11111111 11111111 00000000 00000000

而我希望它是:

11111111 11111111 11111111 00000000 00000000 11111111 11111111

有什么想法吗?

英文:

I am building a simple key-value store for fun. Right now, I am looking for an efficient way to insert a slice in a file.

My current approach:

  • find the desired offset

  • store in a buffer the blocks that precede the desired insert point

  • append the byte slice to that buffer

  • append the rest of the file

  • Write to disk

Problem is:

  • It is not a given that the whole file can fit in memory

  • It is inefficient

I have looked into available libraries and sadly the best match I have found os.WriteAt overwrites the following blocks. Example:

import "os"

func main() {
    pathToFile := "./tmp"
    bufferToWrite := []byte{255, 255, 255, 255, 255}

    f, _ := os.OpenFile(pathToFile, os.O_CREATE|os.O_RDWR, os.PermMode)
    defer f.Close()
    f.Write(bufferToWrite)

So, at this point the content of tmp will be (after $: xxd -g 1 -b tmp):

> 11111111 11111111 11111111 (x) 11111111 11111111

Let's try to insert something with offset = 3 (x):

    bufferToInsert := []byte{0, 0}
    f.WriteAt(bufferToInsert, 3)
}

Output will be:

> 11111111 11111111 11111111 00000000 00000000

And I want it to be:

> 11111111 11111111 11111111 00000000 00000000 11111111 11111111

Any ideas?

答案1

得分: 1

你可以从Git中复制打包文件格式,而不是发明自己的文件格式。

基本思想是有一个索引文件和一个数据文件。当你想要插入一个片段时,只需将其附加到数据文件中。然后更新索引文件,它通常较小。请注意,打包文件不适用于实时更新,但可以与单独的对象文件一起使用。

或者你可以看看伯克利数据库(Berkeley DB)的文件格式。

英文:

Instead of inventing your own file format, you could copy the pack file format from Git.

The basic idea is to have an index file and a data file. When you want to insert a slice you just append it to the data file. Then you update the index file, which is usually smaller. Note that the pack file is not designed for real-time updates, but accompanied by individual object files.

Or have a look at the Berkeley DB file format.

huangapple
  • 本文由 发表于 2016年11月2日 02:49:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/40366652.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定