Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 如何有效地在文件中插入字节片?_Performance_File_Go - Fatal编程技术网

Performance 如何有效地在文件中插入字节片?

Performance 如何有效地在文件中插入字节片?,performance,file,go,Performance,File,Go,为了好玩,我正在建立一个简单的键值存储。现在,我正在寻找一种在文件中插入切片的有效方法 我目前的做法是: 找到所需的偏移量 将所需插入点之前的块存储在缓冲区中 将字节片附加到该缓冲区 附加文件的其余部分 写入磁盘 问题是: 并不是说整个文件都可以放在内存中 这是低效的 我查看了可用的库,遗憾的是,我找到的最匹配的os.WriteAt覆盖了以下块。例如: import "os" func main() { pathToFile := "./tmp" bufferToWri

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

我目前的做法是:

  • 找到所需的偏移量

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

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

  • 附加文件的其余部分

  • 写入磁盘

问题是:

  • 并不是说整个文件都可以放在内存中

  • 这是低效的

我查看了可用的库,遗憾的是,我找到的最匹配的
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-g1-btmp
之后):

11111111111111111111111(x)11111111111111111

让我们尝试插入偏移量为3(x)的对象:

输出将是:

111111111111111111111110000000000000000

我希望它是:

11111111111111111111111 00000000 00000000 11111111111111111111111


有什么想法吗?

您可以从Git复制pack文件格式,而不是发明自己的文件格式

基本思想是有一个索引文件和一个数据文件。当您想插入一个切片时,只需将其附加到数据文件中。然后更新通常较小的索引文件。请注意,包文件不是为实时更新而设计的,而是伴随着单个对象文件


或者看看Berkeley DB文件格式。

编写一个新文件然后替换旧文件要容易得多(通常更安全、更高效),而不是试图插入数据并移动整个文件的其余部分。我有点担心每次用户希望插入新文件(键、值)时都会频繁创建新文件或者更新一个现有的,因为我认为这会增加这些操作的延迟太多。虽然我不是专家,但我知道磁盘上的I/O最好保持在最低限度?问题在于将值“插入”到文件中的概念——常规文件没有插入操作。您所做的任何“插入”都将平均重写50%的文件,如果在重写过程中出错,您将丢失数据。如果您需要经常在存储中的任意点插入内容,您可能正在寻找某种类型的数据库。@JimB谢谢-这正是我正在尝试做的(构建数据库)。这只是为了好玩,虽然它不应该成为生产准备;这只是为了学习,然后你需要从一些用于数据库存储的数据结构开始。B树、索引文件等。谢谢罗兰,我会调查的。我会把你的答案写进一对夫妇中——现在就把它打开,这样人们仍然可以发表他们的建议。现在我想的是有一个如下的索引文件:[index:4字节][offset:2字节],其中
offset
是条目在另一个文件中的位置。这比处理价值观要好得多。你怎么看?忘了这一点:我想稍后允许用户提供一个比较器函数,根据它他们可以对其
key:value
进行排序。现在,
index
将只是一个
uint32
,我根据相应值的二进制表示来计算。您的数据结构取决于键和值的大小。对于值,我通常保留32位,对于偏移量保留64位。但是,这样一个索引项的总大小应该是二的幂,所以我会选择
{offset uint64;size uint32;reserved uint32}
@erwanaron:有无数的出版物和课程涵盖这些内容。在随机尝试创建数据库格式之前做一些研究可能是好的,因为这是一个非常广泛的主题。@JimB我不能向学术论文提出关于设计或良好实践的问题。如果你不想回答,那很好,但正如你所说,这是一个如此广泛的话题。。。我看不出向经验丰富、知识渊博的人征求意见有什么害处。目标不是构建下一个MySQL。只是为了让我学习并获得更多使用低级I/O的经验。
    bufferToInsert := []byte{0, 0}
    f.WriteAt(bufferToInsert, 3)
}