重新排序文件中的数据段

时间:2011-12-09 18:32:25

标签: c# java c++ language-agnostic

我正在尝试用C,C ++,C#,Java中的一个例子或任何语言来寻找一个算法来帮助解决我一直面临的重新排序问题。

目标是在文件中采用一系列范围,并以新模式重新组织,基本上在不破坏数据完整性的情况下移动数据。我宁愿找到一个可以就地执行它并使用单个缓冲区进行交换,或者从一个地方直接移动到另一个地方。只要范围具有​​相同的长度和完整时的数据完整性,重组过程就可以将范围分解为多个部分。

举个例子,给出一组值:

  Length    SrcStart     Src End   Dst Start     Dst End
    9178      274054      283231           0        9177
  274051           0      274050        9178      283228
  582929      283229      866157      283229      866157
  399208      874397     1273604      866158     1265365
    8239    14675709    14683947     1265366     1273604
  986980     1273605     2260584     1273605     2260584
  602862     2811144     3414005     2260585     2863446
  138712     4092072     4230783     2863447     3002158
  116210     3414007     3530216     3002159     3118368
  550559     2260585     2811143     3118369     3668927
  561856     3530217     4092072     3668928     4230783
24319165     4230784    28549948     4230784    28549948
  578539    30246149    30824687    28549949    29128487
  491856    28549949    29041804    29128488    29620343
  593580    29639113    30232692    29620344    30213923
  597308    29041805    29639112    30213924    30811231
   13456    30232693    30246148    30811232    30824687
  633513    31407949    32041461    30824688    31458200
  583261    30824688    31407948    31458201    32041461
40117358    32041462    72158819    32041462    72158819

SrcStart中的所有内容 - >需要将SrcEnd范围移动到DstStart - > DstEnd范围。请注意,在许多情况下,从源到目标的转换将导致目标的内容被更改,您无法再从该位置复制,因为所需的原始数据已被破坏。

目标是将每个数据段从SrcStart移动到DstStart,并在第一列中显示Length。每一行的相应“结束”只是开始加上长度减一(所以它是实际的偏移量)。

我已经做了相当多的研究,并研究了交换值,并分解了与其他值交叉的区域以及容器交换中的容器,但它们似乎不足。所以,结果,这让我回到我的第一个声明,我希望可能有一个算法或一些来源,我可以从中学习以帮助解决这个问题,并且社区的共享知识似乎就是这样去吧。

谢谢!

3 个答案:

答案 0 :(得分:0)

您可以使用磁盘碎片整理程序使用的方法。

  • 首先将您需要覆盖的数据复制到空闲区域
  • 更改引用该数据的所有索引以指向新位置,以便将来使用该副本。
  • 如果系统有这样的概念,您可能需要记下是否有任何块变为“未使用”。

但是,如果索引是以字节为单位,则表示整个文件只有80 MB。一个小文件可以很快复制(少于两秒)也许真正的例子要长得多。文件总共有多大?

答案 1 :(得分:0)

你问这个问题好像是一个不透明的二进制文件,其中由于某种原因你想要交换块。事实似乎不太可能。当然文件有自己的一些结构?你不能利用它来帮助你记账吗?

  • 文件是否具有“已​​使用”和“未使用”区域的概念?
  • 文件是否具有块头的内部结构?
  • 文件是否有任何关联索引或需要保持同步的任何内容? (如果没有,你从哪里得到要移动的街区列表?)
  • 块可以相互重叠吗?请注意,如果他们的操作顺序变得很重要。

那就是说,@ Peter Lawrey推荐的方法很好。如果覆盖块,首先将其复制到文件中的另一个位置,更新任何重叠索引。

总之,在我看来,你试图解决一个难题,将其分解为两个步骤,一个简单,另一个......更难。最初的问题是什么?

(强制性建议:在Windows上,可能会使用事务性IO API)。

答案 2 :(得分:0)

我认为以下算法可以处理它最多两倍的最大卡盘大小内存来缓存数据。除了数据缓存之外,您还需要一本簿记FIFO和原始列表。它类似于:

  1. 如果FIFO和移动表都为空,请完成。
  2. 如果FIFO为空,则将移动表中的顶部条目移至FIFO,同时将条目数据读出到数据缓存中。
  3. 检查移动表中FIFO中第一个条目的目标区域是否有任何块重叠。
  4. 如果有块,请将块的数据读入缓存,将条目移至FIFO,转到3.
  5. 如果没有块,则将FIFO条目的数据从缓存写入目标,删除第一个FIFO条目,转到1.
  6. 我们的想法是找到占用的块,缓存它们以打开空间,并尽快摆脱缓存中的数据。您可能需要添加一些健全性检查以查看源地址和目标地址是否相同。您可能还需要进行其他检查以查看原始表是否有意义(两个块移动到同一位置等)。


    编辑:我可能乐观地说明最大的两次估计最大块时间。我认为它可以超越这一点。我认为时间3是一个简单(但是宽松)的上限。

    由于源表中包含相当大的块,因此可以将它们拆分以减少缓存使用量。比如,您想要使用最多1 GB的缓存:在运行算法之前,将大于1 / 3GB的所有块拆分为多个1 / 3GB长度的条目。或者,您可以使算法以子块大小工作(而不是将完整块读取到缓存中,只读取相关部分,并在源表中保留已修改的条目),但我认为这将更难管理/实施