巨大なファイルをコピーせずに互いに追加する


41

それぞれ約10Gの5つの巨大なファイル(file1、file2、.. file5)があり、ディスク上に非常に低い空き領域が残っているため、これらすべてのファイルを1つに連結する必要があります。元のファイルを保持する必要はなく、最後のファイルのみを保持します。

いつもの連結は一緒に行くされcatたファイルの順序でfile2.. file5

cat file2 >> file1 ; rm file2

残念ながら、この方法では、少なくとも10Gの空きスペースが必要です。実際にコピーせずにファイルを連結する方法はありますが、ファイルシステムに、file1が元のfile1の終わりで終了せず、file2の開始で続行することを何とか伝えますか?

追伸 重要な場合、ファイルシステムはext4です。


2
私は解決策に興味がありますが、ファイルシステムを直接いじらないと解決できないと思います。
ケビン

1
なぜ非常に大きな単一の物理ファイルが必要なのですか?連結を避けることができるかもしれないので、私は尋ねています。これは、現在の答えが示すように、かなり面倒です。
リオリ

6
@rush:この回答かもしれないのヘルプ:serverfault.com/a/487692/16081
liori

1
device-mapperに代わる、効率は劣りますが、実装が容易であり、パーティション化可能なデバイスになり、リモートマシンから使用できるのは、の「マルチ」モードを使用することですnbd-server
ステファンシャゼラス

1
これはクールだと思うと、彼らはいつも私を愚かだと呼びます。
-n611x007

回答:


19

残念ながら、(残念ながら)ファイルを最初から切り捨てることはできません(これは標準ツールには当てはまりますが、syscallレベルについてはこちらを参照してください)。ただし、多少の複雑さを加えることで、通常の切り捨てを使用できます(スパースファイルと一緒に)。すべてのデータを書き込まずに、ターゲットファイルの最後に書き込むことができます。

最初に両方のファイルが正確に5GiB(5120 MiB)であり、一度に100 MiBを移動するとします。で構成されるループを実行します

  1. ソースファイルの末尾からターゲットファイルの末尾に1ブロックをコピーします(消費されるディスク領域を増やします)
  2. ソースファイルを1ブロックずつ切り捨てます(ディスク領域を解放します)

    for((i=5119;i>=0;i--)); do
      dd if=sourcefile of=targetfile bs=1M skip="$i" seek="$i" count=1
      dd if=/dev/zero of=sourcefile bs=1M count=0 seek="$i"
    done
    

ただし、最初に小さいテストファイルで試してください。

おそらくファイルは同じサイズでもブロックサイズの倍数でもありません。その場合、オフセットの計算はより複雑になります。seek_bytesそしてskip_bytes、次に使用する必要があります。

これがあなたが行きたい方法であるが、詳細についての助けが必要な場合は、もう一度尋ねてください。

警告

ddブロックサイズに応じて、結果のファイルは断片化の悪夢になります。


これは、ファイルを連結する最も受け入れられる方法のようです。アドバイスをありがとう。
ラッシュ、

3
何のスパースファイルのサポートが存在しない場合、あなたは代わりに第二のファイルを逆賢明なブロックができ、その後、ちょうど最後のブロックを削除し、第二のファイルに追加
ラチェットフリーク

1
私は自分でこれを試していませんが(しようとしていますが)、seann.herdejurgen.com/resume/samag.com/html/v09/i08/a9_l1.htmは、このアルゴリズムを実装すると主張するPerlスクリプトです。
zwol

16

プログラムで複数のファイルを処理できない場合は、ファイルを1つのファイルにまとめる代わりに、名前付きパイプを使用して1つのファイルをシミュレートすることもできます。

mkfifo /tmp/file
cat file* >/tmp/file &
blahblah /tmp/file
rm /tmp/file

Haukeが示唆するように、losetup / dmsetupも機能します。簡単な実験; 私は 'file1..file4'を作成し、少し努力しました:

for i in file*;do losetup -f ~/$i;done

numchunks=3
for i in `seq 0 $numchunks`; do
        sizeinsectors=$((`ls -l file$i | awk '{print $5}'`/512))
        startsector=$(($i*$sizeinsectors))
        echo "$startsector $sizeinsectors linear /dev/loop$i 0"
done | dmsetup create joined

次に、/ dev / dm-0には、ファイルをコンテンツとして含む仮想ブロックデバイスが含まれます。

私はこれをよくテストしていません。

別の編集:ファイルサイズは512で均等に分割できる必要があります。そうしないと、一部のデータが失われます。もしそうなら、あなたは大丈夫です。彼はまた、以下のことにも言及していると思います。


このファイルを一度読むのは素晴らしい考えです。残念ながら、fifoを前後にジャンプすることはできませんよね?
急ぎます

7
@rush優れた代替方法は、各ファイルにループデバイスを配置し、それらをdmsetup仮想ブロックデバイスに結合することです(通常のシーク操作は可能ですが、追加も切り捨てもでき​​ません)。最初のファイルのサイズが512の倍数でない場合は、不完全な最後のセクターと最初のバイトを2番目のファイル(合計512)から3番目のファイルにコピーする必要があります。2番目のファイルのループデバイスが必要に--offsetなります。
ホークレイジング

エレガントなソリューション。最初のファイルのサイズが512の倍数でない場合に問題を回避する方法を提案するHauke Lagingにも+1
オリビエデュラック

9

あなたが持っている空きスペースの量と同じくらい大きい束にデータをコピーする何かを書かなければなりません。次のように動作するはずです。

  • データのブロックを読み取りますfile2pread()読み取りの前に正しい場所にシーク​​することにより使用)。
  • ブロックをに追加しますfile1
  • fcntl(F_FREESP)からスペースの割り当てを解除するために使用しますfile2
  • 繰り返す

1
私は知っています...しかし、私はコードを書くことを伴わない方法を考えることができませんでした、そして、私は自分が書いたものを書くことは何も書かないほうが良いと思いました。最後から始めるという巧妙なトリックは考えていませんでした!
セラダ

あなたも、最後から始めないと機能しませんか?
ハウケレイジング

いいえ、fcntl(F_FREESP)ファイルの特定のバイト範囲に関連付けられたスペースを解放するため、最初から機能します(スパースにします)。
セラダ

それはいいね。しかし、これは非常に新しい機能のようです。私のfcntlマニュアルページ(2012-04-15)には記載されていません。
Hauke Laging

4
@HaukeLaging F_FREESPはSolarisのものです。Linux(2.6.38以降)では、fallocatesyscallのFALLOC_FL_PUNCH_HOLEフラグです。fallocateユーティリティの新しいバージョンには、util-linuxそれに対するインターフェースがあります。
ステファンシャゼラス

0

私はそれがあなたが求めたものよりも回避策のほうが多いことを知っていますが、それはあなたの問題の世話をします(そしてほとんど断片化や頭痛なしで):

#step 1
mount /path/to/... /the/new/fs #mount a new filesystem (from NFS? or an external usb disk?)

その後

#step 2:
cat file* > /the/new/fs/fullfile

または、圧縮が役立つと思われる場合:

#step 2 (alternate):
cat file* | gzip -c - > /the/new/fs/fullfile.gz

その後(そしてその後のみ)、最後に

#step 3:
rm file*
mv /the/new/fs/fullfile  .   #of fullfile.gz if you compressed it

残念ながら、外部USBディスクには物理的なアクセスが必要で、nfsには追加のハードウェアが必要で、私には何もありません。とりあえずありがとう。=)
急ぎます

私はそれがそのようになるだろうと思った...ロブ・ボスの答えはあなたの最良の選択肢を思われるもの、その後で(切り捨て-ながら、コピーして負けたデータを危険にさらすことなく、としてFSの制限を打つことなく、ウェル)
オリヴィエ・デュラック
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.