我在这里使用预先存在的文件系统,所以我无法改变它的结构。我还使用RandomAccessFile对象在Java中工作。
一个文件可以容纳许多独立的数据块。我知道在哪里可以找到正确的文件和每个单块的开头没有任何问题,并且知道它的确切大小。该文件分为4 KB和#34;扇区"数据只能从扇区的开头开始。大块的数据大小不一。这一切都很好,直到尺寸变化到足以保持它所需的扇区数量变化......一个块可以是4到256个扇区之间的任何地方,所以我可以给出一个小问题每个块的额外空间,以防它增长。
我需要找到一种方法将这个已编辑的块保存回文件,但它不适合以前的位置,所以我必须腾出空间。我可以轻松更新所有元数据,告诉我现在存储的所有内容,这不是问题。问题是,我不知道在此文件中转换数据的有效方法。该文件将包含1024个数据块,每个数据范围为4到256个扇区(16 KB到1 MB)。因此,此文件的大小可能为1 GB。一次性加载文件是不可能的。
我的第一个想法是做一种涟漪效应。让Chunk A成为我现在正在保存一个更大的修改版本的。在我的程序中保留一个扇区的内存,在Chunk A的旧位置之后加载第一个扇区,将其保存在Chunk A用于启动的位置,并继续将后续扇区移回到结束时文件,然后最终将新部门打到最后。我无能为力,但觉得这个想法非常低效。有人有更好的吗?
如果它有帮助,我可以轻松,恒定地访问文件中每个块的位置以及每个块占用的扇区数。它全部在文件头中。
答案 0 :(得分:1)
其中一个想法是每次修改都会创建一个新文件。所以说你经历了修改周期,一旦完成,你就创建了一个新文件,并将所有已修改的块写入新文件中并使用新订单和日志(跟踪块块坐标)修改为新文件。
优点:为您提供每次修改的历史记录,相对简单的逻辑
缺点:如果修改的块是整个文件的一小部分,则磁盘空间效率低,写入效率可能低。
到目前为止,更复杂的想法是仅存储原始文件和每个修改的增量序列。然后在检索时,你必须根据它的原始状态和与这个特定块相关的增量来动态构建块的状态
答案 1 :(得分:1)
您所描述的问题几乎就是碎片问题。或许我应该说碎片通常是在数据发生变化时避免过度移动数据的结果。您可以做的最好的事情是查看磁盘和内存碎片的现有解决方案以获得想法。只要计算机具有存储(包括易失性和持久存储),这就是一个存在的问题,因此它得到了很好的研究。
在文件系统上,文件将与您的chunks
数据相对应,文件表格是header
的一种形式。文件系统能够将文件分解为不必在磁盘上形成连续块的片段。由于您无法更改必须维护的文件格式,因此您无法分解块并将一个块末端的指针保持为其延续。但是当更改文件使其变得比当前适合的文件大时,文件系统显然不会移动所有后续文件以腾出空间。这将是一个非常昂贵的操作。同样地,您不希望在编辑完成后移动所有块。因为机械媒体(旋转磁盘)的物理磁盘访问变得越来越低效,如果属于一起的数据(例如一个文件)到处都是,偶尔的碎片整理应用于移动文件以更有效地使用空间的耗时任务是一批进行的。
在内存中,程序必须分配内存才能使用。操作系统可以从物理内存空间中获取可用内存块,并将其呈现给它所托管的程序,就像每个程序都有自己的连续内存空间一样。这是一个必要的抽象,以确保程序可以独立运行而无需相互跟踪。程序不断地分配空间并在处理数据时取消分配空间,这会导致可用内存碎片化。但是,有时需要一定量的连续内存(如程序所示),就像大字节数组一样。如果程序的存储空间中不存在这样的可用存储块,则必须移动数据直到空闲存储器在足够大的块中汇集在一起。如果无法完成,则会出现内存不足错误。有关如何完成这些工作的一些想法,请调查C programming language memory allocation functions。
以上内容如下所示:如果您不必,请不要尝试将文件始终保持在最佳状态,但是时间允许或情况如何要求它,重新安排它。
让我们来看一个例子。假设您有3个块,分别为4,8和6个扇区。标题跟踪每个块开始的位置。
我们现在编辑块2,它变成10个扇区。它不再适合当前的空间。因此,我们通过该文件查找第一个地址,其中有足够的可用空间用于10个扇区,将编辑的块移动到那里并更新标头。请注意,旧数据可以保留或可以消隐。
为了找到第一个足够大的空闲空间块来容纳新的或编辑过的块,我们需要调查标头以映射文件中的内存使用。例如,新情况会留下8个未使用的扇区,从地址4到11.如果找不到足够大的空闲空间块,则将块放在最后。然后该文件必须增大。
那么我们如何控制碎片呢?必须偶尔分析文件空间的使用情况。使用标题并可能在更新期间保留一些元数据,这可能非常简单,并且不会进行太多处理。如果满足某些条件(例如,文件的20%由未使用的扇区组成),则启动一轮碎片整理。如果必须将一个块放在文件的末尾,但没有剩余空间(使用1 GiB),则首先尝试进行一轮碎片整理,然后移动已编辑的块或添加新块。如果碎片整理没有释放足够的空间,您就会遇到限制(如程序中的内存不足错误)。
碎片整理方法可能非常简单或聪明,具体取决于它需要多快。简单的方法是:按照文件中出现的顺序移动每个块,使其从前一个块的末尾开始。
这可以保证在您完成文件后,文件的大小可能会最小。但是,因为它没有留下打开的房间"当你第一次以一种大块的方式编辑一个块时,你会再次引入碎片,因为根据定义它不再适合(除非它是文件中的最后一个)。此外,它将从第一个在其前面有空白空间的块开始移动所有块,因此这是一项昂贵的操作。
您可以尝试使用更智能的方法来获得更快的速度,例如从文件末尾浏览块,并在从文件开头搜索时将每个块移动到最适合它的空白区域。这不会移动所有块。一些未使用的空间将保留,但比以前少。
如何为碎片整理算法建模取决于您的用例。您甚至可以动态选择,例如在达到最大文件大小时采用繁重的方法,如果只是超过某个未使用空间的阈值,则采用更快,更轻的算法。