英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论