java - 在文件中重组数据

标签 java file

我正在使用一个预先存在的文件系统,因此无法更改其结构。我也在Java中使用RandomAccessFile对象工作。

一个文件可以容纳许多独立的数据块。我知道在哪里可以找到正确的文件以及每个单独的块的开头,没有任何问题,并且知道其确切大小。该文件分为4 KB的“扇区”,其中数据只能从扇区的开头开始。数据块的大小各不相同。一切都很好,直到大小变化到足以容纳它所需的扇区数为止……一个块可以在4到256个扇区之间的任何地方,所以我可以给每个块额外的空间并不是一件容易的事万一它增长了。

我需要找到一种方法来将已编辑的块保存回文件中,但是它不适合以前的位置,因此我必须腾出空间。我可以轻松地更新所有告诉我现在所有内容都存储在何处的元数据,这不是问题。问题是我不知道在此文件中转移数据的有效方法。该文件将包含1024个数据块,每个数据块的范围从4到256个扇区(16 KB到1MB)。因此,该文件的大小可能为1 GB。一次全部加载文件是不可能的。

我的第一个想法是产生某种连锁反应。让Chunk A成为我现在要保存的更大的修改版的那个。在我的程序中保留一个扇区的内存,在Chunk A的旧位置之后加载第一个扇区,将其保存在Chunk A以前开始的位置,然后继续将后续扇区移回文件末尾,然后最终定位新扇区到最后。我忍不住觉得这个主意太低了。有人有更好的吗?

如果有帮助,我可以轻松,恒定地访问文件中每个块的位置以及每个块占用多少扇区。全部在文件头中。

最佳答案

您正在描述的问题几乎就是碎片问题。也许我应该说,碎片通常是避免在数据更改时过度移动的结果。最好的办法是查看有关磁盘和内存碎片的现有解决方案,以获取启发。只要计算机具有存储( Volatile 和持久性),就存在这个问题,因此对此进行了深入研究。

在文件系统上,文件将与您的chunks数据相对应,文件表是header的一种形式。文件系统具有能够将文件分解为多个部分的优点,这些部分不必在磁盘上形成连续的块。由于您无法更改必须维护的文件格式,因此无法选择拆分块并在块的末尾保留指向其延续的指针。但是,当更改文件使其变得大于当前的大小时,文件系统显然不会移动所有后续文件来腾出空间。那将是非常昂贵的操作。同样,您也不想在编辑所有块之后四处移动。如果到处都是属于一起的数据(例如对于一个文件),由于对机械介质(旋转磁盘)的物理磁盘访问变得效率越来越低,因此偶尔会进行碎片整理,在移动文件以更有效地利用空间这一费时的任务上一批执行。

在内存中,程序必须分配内存才能使用。操作系统可以从物理内存空间中获取大块可用内存,并将其提供给它托管的程序,就好像每个程序都有自己的连续内存空间一样。这是必要的抽象,以确保程序可以独立运行而不必相互跟踪。程序在处理数据时会不断分配空间并取消分配空间,这会导致可用内存碎片。但是,有时需要一定数量的连续内存(如程序所示),例如大字节数组。如果程序的存储空间中不存在这样的可用内存块,则必须移动数据,直到空闲内存在足够大的块中池在一起为止。如果无法做到这一点,则会出现内存不足的错误。有关如何完成这些操作的一些想法,请研究C programming language memory allocation functions

上面的内容是这样的:如果不需要的话,不要一直将文件保持在最佳大小,而是在时间允许或情况需要时重新安排它。

让我们看一个例子。假设您有3个块,分别为4、8和6个扇区。标头跟踪每个块的起始位置。

initial situation

现在,我们将编辑块2,它的长度为10个扇区。它不再适合其当前空间。因此,我们遍历该文件以找到第一个地址,该地址有足够的可用空间用于10个扇区,将已编辑的块移到该地址并更新标题。请注意,旧数据可以保留或保留为空白。

new situation

为了找到足够大的第一个空闲空间来容纳新的或已编辑的块,我们需要研究头文件,以映射出文件中的内存使用情况。例如,新情况留下了8个未使用的扇区,从地址4到11。如果找不到足够大的可用空间块,则将块放在最后。然后,该文件将不得不增大大小。

那么,如何控制碎片化呢?偶尔需要分析文件空间使用情况。使用标头并在更新过程中保留一些元数据,这可能非常简单,并且不需要太多的处理。如果满足某些条件(例如,文件的20%由未使用的扇区组成),则将启动一轮碎片整理。如果必须在文件的末尾放置一个块,但没有剩余空间(已使用1 GiB),则首先尝试进行一堆碎片整理,然后移动已编辑的块或添加新的块。如果碎片整理没有释放足够的空间,则您将遇到限制(例如程序中的内存不足错误)。

碎片整理方法可能非常简单,也可能很聪明,具体取决于它需要多快。很简单:将每个块按文件中出现的顺序移动,使其从前一个文件的末尾开始。

moving chunks

这样可以保证完成后文件的大小最小。但是,由于它没有“开放空间”,因此您将在第一次编辑块时以更大的方式再次引入碎片,因为根据定义,它不再适合(除非它是文件中的最后一个) )。而且,它将移动所有块,从第一个块前面开始有空白的块开始,因此这是一项昂贵的操作。

您可以尝试使用更智能的方法来提高速度,例如从文件末尾遍历各个块并将每个块移入最适合从文件开头进行搜索的空白区域。这不会移动所有块。一些未使用的空间将保留,但比以前少。

如何对碎片整理算法建模取决于您的用例。您甚至可以动态选择,例如达到最大文件大小时采用繁重的方法,如果您只是超出一定的未使用空间阈值,则可以采用更快,更轻便的算法。

关于java - 在文件中重组数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42488368/

相关文章:

java - 为什么java编译器不识别字段已初始化?

java - Kafka Producer请求超时设置

c - C中的长整数

php - 如何在 PHP 中将 MySQL 数据库备份到文件?

python - 如何创建 CSV 文件的标题?

Java HttpConnection/HttpsConnection 输入/错误流

java - 如何避免使用 Hibernate 自动生成值检查 id

java - 从 android 到 PHP 的 HTTP post 调用?

python - 在 Python 中读取和打印与 USB 相关的 var 日志消息

c - 在txt文件中保存计数器