删除文件中间的字节而不移动末尾



例如,如果我有很多数据条目存储在一个文件中,每个都有不同的大小,我有1000个条目,这使得文件像100MB大,如果我想删除文件中间的一个条目,大小为50KB,我怎么才能删除文件中空白的50KB字节而不移动所有的结束字节来填充它?

我使用winapi函数来管理文件:

CreateFile, WriteFile, ReadFileSetFilePointerEx

如果您确实想这样做,请在条目中设置标志。当您想从文件中删除一个条目时,只需使该标志(逻辑删除)无效,而不需要物理删除它。下次添加条目时,只需遍历文件,查找第一个无效条目,并覆盖它。如果所有都已验证,则将其附加到末尾。这需要O(1)的时间来删除一个条目,O(n)的时间来添加一个新条目,假设从/到磁盘读写单个条目是基本操作。

你甚至可以进一步优化它。在文件的开头,存储一个位映射(1表示无效)。例如,0001000...表示文件中的第4个条目无效。当您添加一个条目时,在位映射中搜索第一个1,并使用随机文件I/O(与顺序文件I/O相反)将文件指针重定向到该条目以直接覆盖。这样添加只需要O(1)的时间。

哦,我注意到你的评论了。如果您希望通过物理删除条目来高效地完成这项工作,一个简单的方法是将与文件中的最后一个条目交换并删除最后一个条目,假设您的条目没有排序。时间也很好,添加和删除都是O(1)

编辑:就像Joe提到的,this requires that all of your entries have the same size。您可以使用可变长度的条目来实现,但这将比这里讨论的更复杂。

设A =文件的开始,B =要删除的块的开始,C =要删除的块的结束

CreateFile with flag FILE_FLAG_RANDOM_ACCESS

SetFilePointerEx到位置C,读到EOF到缓冲区(考虑到你的文件大小,这可能是一个很大的缓冲区)。对于庞大的记录要小心,因为任何File IO操作现在都必须分配记录大小的虚拟内存来执行任何简单的操作(如move)。

将缓冲区复制到文件

中的位置B

现在应该在位置B + sizeof(block C).调用SetEndOfFile在该位置截断文件,然后关闭。

请注意,使用memmove函数可以更容易地完成此操作。但是,这需要您将整个文件映射到内存中,进行移动,然后将其写回来。这对于小文件来说非常好,但是对于大于50-100MB的文件,我要提醒您要有足够的可用连续虚拟地址空间。

您可以简单地继续标记未使用的空间,并且在一段时间后,当内部碎片超过一定比例时,您可以运行一个例程来压缩文件。使用这种方案,清除将是快速的,但需要一些周期性的重组。如果您有一个单独的文件处理方案,那么您可以将文件划分为一些块,然后跟踪空闲块,并在删除时将块标记为未使用并跟踪它,然后在插入的情况下重用它。此方案将取决于文件中记录的类型,固定或可变长度记录。

相关内容

  • 没有找到相关文章

最新更新