スパースファイル

提供: ArchWiki
2024年7月10日 (水) 20:26時点におけるKusanaginoturugi (トーク | 投稿記録)による版 (校正(でき・出来))
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)
ナビゲーションに移動 検索に移動

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
警告: `loop' オプションを必ず指定して下さい -- 指定しなかった場合、マウントされません。

スパースファイルのコピー

`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 のようなプログラム
https://github.com/anyc/sparse-fio || sparse-fio-gitAUR
  • sparseutils — まばらに配置されたファイルを操作するためのユーティリティ。mksparse.pysparsemap.py を提供し、pip でインストールできます。
https://pypi.org/project/sparseutils/ || パッケージが存在しないか AUR で検索

参照