ネットワーク速度、ディスクの読み書き性能、プログラムの動作性能などをテストするために、指定したサイズのファイルが必要になることがあります。そのとき、まず思い浮かぶのは dd でしょう? しかし、dd でファイルを作ると遅いと感じませんか? さらに、dd のほかに truncate や fallocate も使えることをご存じでしょうか? この記事では、大きなファイルを生成する方法、その使い方、そしてそれぞれの違いを簡単に説明します。なお、ここで生成するファイルの内容には意味がないことにご注意ください。
大きなファイルの生成でよく挙げられるのは dd コマンドです。dd の本来の目的は、ディスクのある場所からデータを別の場所へコピーすることで、cp に似ています。ただし dd はディスクのセクタというより低いレベルから処理するため、情報を取りこぼすことがありません。この dd を利用して、1MB の内容を 1024 回コピーすれば、1GB のファイルができあがります!
if は input file(入力ファイル)、of は output file(出力ファイル)の意味です。Linux には /dev/urandom という特別なファイルがあり、ランダムなデータを生成してくれます。次のコマンドは、1M 単位の /dev/urandom を 1024 回繰り返して、1G.img というファイルに書き込みます。
dd if=/dev/urandom of=1G.img bs=1M count=1024
ただし、この方法は遅すぎます。if を /dev/zero に変えると速度が上がります。乱数はシステムが生成する必要がありますが、0 を直接書き込む方が速いためです。
dd if=/dev/zero of=1G.img bs=1M count=1024
それでも /dev/zero に変えただけでは、まだ十分に速くありません。特にファイルを大きくするほど遅くなります。理由は単純で、dd は実際にディスクのセクタから内容を読み出してコピーするため、実行速度はディスクの I/O に左右されます。そして、ディスクの I/O が遅いのは周知のとおりです……。この問題を解決して、偽のファイルの生成速度をファイルサイズに左右されないようにするには、スパースファイル(疎なファイル)という方法を使います。簡単に言うと、dd /dev/zero では内容のあるファイルを実際に作成しますが、内容を持たず「10G ある」と主張するファイルも作成できるのです。
これは dd と truncate のどちらでも実現できます。
dd if=/dev/zero of=1Gfile bs=1 count=0 seek=1G truncate -s 1G 1Gfile
ls -lh で確認すると、確かに 1G のファイルになっています。ダウンロードしても、確かに 1G のファイルを取得できます。しかし du で実際のディスク使用量を調べると、中身はほぼ空であることがわかります! そのため、ディスクの容量より大きいファイルも作成できます。たとえば 100G の容量のディスクでも、10TB のファイルを作ることができます。
生成を速くしつつ、実際にディスク容量を「占有」させたい場合は fallocate を使えます。fallocate は指定された容量をディスクに実際に確保しますが、その容量を実際に使うわけではありません。fallocate は、私がおすすめする方法でもあります。
fallocate -l 10G 10G.img
macOS を使っている場合は dd か mkfile を使えます。macOS では truncate と fallocate はサポートされていません。
mkfile -n 1g 1G.img
参考までに、速度の比較を掲載します。
補足:truncate や fallocate で作成したファイルには実際の内容がありませんが、ディスクの読み書き速度やネットワークのダウンロード速度のテストには影響しません。スパースファイルと実際に内容のあるファイルの違いがどこに現れるのかは、私もまだ考えている途中です。この点について情報をお持ちの方は、ぜひ教えてください!

