例如,如果我有大量的数据条目存储在一个文件中,每个都有不同的大小,我有1000个条目,使文件像100MB大,如果我然后想要删除文件中间的条目是50KB的大小,我怎样才能删除文件中空的50KB字节而不移动所有结束字节来填充它?
我正在使用诸如此类的winapi函数进行文件管理:
CreateFile
,WriteFile
,ReadFile
和SetFilePointerEx
答案 0 :(得分:7)
如果您真的想这样做,请在条目中设置标记。如果要从文件中删除条目,只需使该标志无效(逻辑删除),无需物理删除。下次添加条目时,只需浏览该文件,查找第一个无效条目,然后覆盖它。如果所有都经过验证,请将其附加到最后。这需要O(1)
时间来删除条目,并O(n)
添加新条目,假设从/向磁盘读取/写入单个条目是基本操作。
您甚至可以进一步优化它。在文件的开头,存储位图(1
表示无效)。例如,0001000...
表示文件中的第4个条目无效。添加条目时,在位图中搜索第一个1
并使用Random file I/O(与顺序文件I / O 相反)将文件指针重定向到该位直接进入覆盖。以这种方式添加只需O(1)
次。
哦,我注意到你的评论。如果您希望通过物理删除条目有效地执行此操作,一种简单的方法是交换条目中的最后一个删除条目并删除最后一个,假设您的条目不是排序。时间也很好,添加和删除都是O(1)
。
修改:正如Joe所说,this requires that all of your entries have the same size
。你可以实现一个具有可变长度条目的条目,但这比这里讨论的要复杂得多。
答案 1 :(得分:1)
设A =文件的开头,B =要删除的块的开始,C =要删除的块的结束
带有标记CreateFile
的 FILE_FLAG_RANDOM_ACCESS
SetFilePointerEx
到位置C,读取到EOF到缓冲区(考虑到文件大小,这可能是一个大缓冲区。请注意巨大的记录,因为任何文件IO操作现在都必须分配记录大小的虚拟内存做任何简单的操作,比如移动)。
将缓冲区复制到文件
中的位置B.现在应该在B + sizeof位置(块C)。调用SetEndOfFile
截断该位置的文件,然后关闭。
请注意,使用memmove函数可以更轻松地完成此操作。但是,这需要您将整个文件映射到内存中,进行移动并将其写回。这对于小文件很有用,但是大于50-100MB的文件我会提醒你有足够的可用连续虚拟地址空间。
答案 2 :(得分:1)
您可以简单地标记未使用的空间,并且在内部碎片超过特定比率的一段时间之后,您可以运行压缩文件的例程。通过这种方案,清除速度很快,但需要进行一些定期重组。如果你有一个单独的文件处理方案,那么你可以在一些块中划分文件然后跟踪空闲块,并在删除时将块标记为未使用并跟踪它,稍后在插入的情况下重用它。此方案将取决于文件中的记录类型,固定或可变长度记录。