スパースファイル
Wikipedia によれば、コンピュータサイエンスにおいて、スパースファイルとはファイルに割り当てられたブロックが空の場合にファイルシステムの領域を効率よく使用するコンピュータファイルのことです。ブロックを実際に"空"の領域で埋めるのではなく、空のブロックであることを示す簡単な情報 (メタデータ) をディスクに書き込むことで、ディスクの使用量を減らします (すなわち、スパースファイルには存在を示すためのゼロブロックだけがあり、ディスク上には全く領域が割り当てられません)。ブロックに"本物"の (空ではない) データが現れたときに、実際にディスクにデータ容量分のブロックサイズが書き込まれます。
スパースファイルを読み込んだときは、ファイルシステムによって、空ブロックを示すメタデータがゼロバイトで満たされた"本物"のブロックに透過的に変換されます。アプリケーションは実際はスパースファイルだということに気が付きません。
ほとんどの近代的なファイルシステムはスパースファイルをサポートしています。主要な Unix ファイルシステムや NTFS などがそうです。ただし Apple の HFS+ は残念ながらサポートしていません。スパースファイルが使われるのは、ディスクイメージ(スパースイメージ と混同しないでください)やデータベースのスナップショット、ログファイルや科学用アプリケーションなどが一般的です。
スパースファイルの利点は、ストレージが使われるのは実際に必要になってからだということです: ディスク容量が節約されて、たとえファイルシステムに十分な空き容量が存在しない場合でも巨大なファイルを作成することができるようになります。
スパースファイルは断片化することがあるという欠点が存在します。ファイルシステムからの偽の空き容量の報告が誤解を生む可能性があります。スパースファイルが含まれたファイルシステムを一杯にしてしまうと予期せぬ事態になるかもしれません。また、スパースファイルに対応していないプログラムでスパースファイルをコピーすると、ディスク上には存在しないゼロの領域 (スパース, 疎) まで完全にコピーしてしまうことが考えられます。これではスパースファイルにした意味がなくなってしまうでしょう。
目次
スパースファイルの作成
truncate ユーティリティでスパースファイルを作成できます。以下のコマンドは 512 MiB のスパースファイルを作成します:
$ truncate -s 512M file.img
dd ユーティリティを使うことも可能です。例:
$ dd if=/dev/zero of=file.img bs=1 count=0 seek=512M
スパースファイルには外見上のファイルサイズ (拡大できる最大容量) と実際のファイルサイズ (ディスク上のデータ容量) という2つのファイルサイズが存在します。ファイルの外見上のサイズを確認するには、次を実行:
$ du -h --apparent-size file.img
512M file.img
そして、ディスク上のファイルの実際のサイズを確認するには:
$ du -h file.img
0 file.img
上記の場合、ファイルの外見上の容量は 512 MiB となっていますが、"実際"の容量は完全にゼロです。スパースファイルでは、ファイルを保存するのに必要な最小容量まで自由にサイズが変えられます。
既存のファイルをスパースファイルにする
ファイルシステムがサポートされている場合 (XFS, ext4, tmpfs)、fallocate ユーティリティを使うことで既存のファイルをスパースファイルに変えることができます:
$ cp file.img copy.img --sparse=never $ du -h copy.img 512M copy.img
$ fallocate -d copy.img $ du -h copy.img 0 copy.img
既存のファイルを非スパースファイルにする
次のコマンドは、(スパース) ファイルを非スパースにコピーを作成します:
$ cp file.img copy.img --sparse=never $ du -h copy.img 512M copy.img
ファイルシステムでファイルをフォーマット
スパースファイルを作成したら、ファイルシステムでフォーマットしましょう。例えば ReiserFS を使う場合:
# mkfs.reiserfs -f -q file.img mkfs.reiserfs 3.6.21 (2009 www.namesys.com)
ファイルシステムのフォーマットによってどんな影響があったかサイズを確認してみます:
# du -h --apparent-size file.img 512M file.img
# du -h file.img 33M file.img
ご推察の通り、ファイルシステムでフォーマットすることで実際のサイズが大きくなりました。しかしながら外見上のサイズは変わっていません。次に、ディレクトリを作成してファイルをマウントしてみます:
# mkdir folder # mount -o loop file.img folder
ジャジャーン。外見上は 512 MiB もある情報を保存することが出来ました。
起動時にファイルをマウント
スパースファイルを作成したら、起動時に自動的にマウントさせることが可能です。以下のように /etc/fstab
にエントリを追加することでマウントできます:
/path/to/file.img /path/to/folder reiserfs loop,defaults 0 0
スパースファイルのコピー
`cp' でコピー
基本的に、`cp' はファイルがスパースであるかどうか検出することができるので、次を実行すると new_file.img はスパースになります:
cp file.img new_file.img
ただし、cp には --sparse=WHEN
オプションが存在します。スパースファイルが実はスパースではない場合 (つまり、空のブロックがディスクに書き込まれている場合) に有用です。次を実行することでディスク領域を回収できます:
cp --sparse=always new_file.img recovered_file.img
`tar' で圧縮
ある日、あなたは長年の連れ添いであるスパースファイルをバックアップしようと思い立ちました。そこで `tar' ユーティリティを使おうと考えたあなたは、はたと問題に出くわします:
# du -h file.img 33M file.img
# tar -cf file.tar file.img
# du -h file.tar 513M file.tar
一見、スパースファイルの容量は 33 MB しかないのに、tar で圧縮すると巨大なファイルが作成されてしまったのです。しかしながら、あなたはツイています。tar には `--sparse' (`-S') フラグが存在するのです。`--create' (`-c') と一緒に使うことで、圧縮時にファイルがスパースでないか全てのファイルを調査します。ファイルがスパースであると tar が認識すると、アーカイブの中ではファイルの代わりにスパースが使われます。これは dbm ファイルなどをアーカイブ化するときに有用です。dbm ファイルは中身がほとんどヌルであり、アーカイブとして保存するときに必要な容量を劇的に減らすことができます。
# tar -Scf file.tar file.img # du -h file.tar 12K file.tar
晴れて問題は解決しました。
スパースファイルの容量の変更
ファイルのサイズを変更する前に、テスト用に小さいファイルを作成してみましょう:
# for f in {1..5}; do touch folder/file${f}; done # ls folder/ file1 file2 file3 file4 file5
そして、ファイルに中身を追加します:
# echo "This is a test to see if it works..." >> folder/file1 # cat folder/file1 This is a test to see if it works...
ファイルの拡大
ファイルを拡大する必要がある場合、以下を実行します:
# umount folder # dd if=/dev/zero of=file.img bs=1 count=0 seek=1G 0+0 records in 0+0 records out 0 bytes (0 B) copied, 2.2978e-05 s, 0.0 kB/s
上記のコマンドでサイズが 1 Gb まで増大します。情報は損なわれません。次に、ファイルシステムのサイズを増加させてください:
# resize_reiserfs file.img resize_reiserfs 3.6.21 (2009 www.namesys.com) ReiserFS report: blocksize 4096 block count 262144 (131072) free blocks 253925 (122857) bitmap block count 8 (4) Syncing..done resize_reiserfs: Resizing finished successfully.
そして再マウント:
# mount -o loop file.img folder
容量を確認すると:
# du -h --apparent-size file.img 1.0G file.img
# du -h file.img 33M file.img
中身を確認すると:
# df -h folder Filesystem Size Used Avail Use% Mounted on /tmp/file.img 1.0G 33M 992M 4% /tmp/folder
# ls folder file1 file2 file3 file4 file5
# cat folder/file1 This is a test to see if it works...
ツール
- sparse-fio — ゼロ以外のデータがまばらに含まれるファイルを処理する dd のようなプログラム
- sparseutils — まばらに配置されたファイルを操作するためのユーティリティ。
mksparse.py
とsparsemap.py
を提供し、pip でインストールできます。
- https://pypi.org/project/sparseutils/ || パッケージが存在しないか AUR で検索