新しい空のファイルを作成するよりも、既存のファイルに書き込む方が速いのはなぜですか?

新しい空のファイルを作成するよりも、既存のファイルに書き込む方が速いのはなぜですか?

私はLinuxでファイルを書くためにMappedByteBufferを使っています。

File file = new File("testFile");
RandomAccessFile raf = new RandomAccessFile(file, "rw");
FileChannel fc = raf.getChannel();
MappedByteBuffer mbf = fc.map(FileChannel.MapMode.READ_WRITE, 0, file.length());
mbf.put(buffer);

testFileに500MBを書き、500MBのデータを2回書き込むと1秒かかります。ただし、testFileを実行すると500MBのデータを書き込むのに4秒かかります。

新しいファイルを書き込むよりもファイルを上書きする方が速いのはなぜですか?ファイルを上書きするように新しいファイルをより速く書き込むにはどうすればよいですか?

答え1

上書きする方が速いか、新しいファイルを作成する方が速いかは、ファイルシステムの種類によって異なります。多くのファイルシステムはファイルデータを上書きする必要があるため、上書きが高速ですが、新しいファイルを作成する前にスペースを割り当ててから、新しい割り当てられたスペースにデータを書き込む必要があります。しかし、大きな違いはないと予想されます。一部のファイルシステムは既存のブロックを上書きしません。キャンセルするには書き込み)次に、新しいデータを書き込み、古いデータを削除して既存のファイルを上書きします。しかし、私は2つの状況の間に大きな違いはないと思います。

基本レイヤーも同様の効果をもたらし、あるタスクを他のタスクよりもコストがかかることがあります。たとえば、スナップショットが保存されているシステムを上書きすると、スナップショットを復元できるように古いデータが保存されます。フラッシュメディアは一括で消去できるため、空のセクタに新しいデータが書き込まれますが、一部のデータを上書きすると最終的に解放されるため時間がかかります。

読み出しと書き込みのタイミングに最も大きな影響を与えるのはバッファリングとキャッシュです。syncホットキャッシュ/バッファのタイミングを測定する場合を除き、既知のキャッシュ構成でベンチマークし(各ベンチマーク操作を開始する前にディスクキャッシュをフラッシュする必要があります)、すべての書き込みのバッファで終了する必要があります(呼び出して実行されます)。たとえば、2回の連続書き込み(最初の書き込みはメモリバッファにのみ書き込む)を実行すると、単一の書き込みを実行するよりもコストがかかりません。

とにかく、欲しいことをするのに4秒かかったら、4秒かかるのです。 4倍速くする魔法のような方法はありません。

答え2

これを使用したクイックテストは、ddファイルにデータを追加する方が高速ではないことを示しています。

私のテストファイルサイズは1024MBです。最終添付ファイルサイズは2048MBです。

creating a new file
real    0m3,052s
user    0m0,523s
sys     0m0,578s

overwriting existing file
real    0m3,510s
user    0m0,695s
sys     0m0,867s

appending to existing file
real    0m3,226s
user    0m0,602s
sys     0m0,594s

deleting file
real    0m0,273s
user    0m0,086s
sys     0m0,195s

テスト.sh:

#!/usr/bin/env bash
printf "creating a new file\n"
time dd if=/dev/zero of=./test.img count=1024 bs=1M && sync -f

printf "\noverwriting existing file\n"
time dd if=/dev/zero of=./test.img count=1024 bs=1M && sync -f

printf "\nappending to existing file\n"
time dd if=/dev/zero bs=1M count=1024 >> ./test.img && sync -f

printf "\ndeleting file\n"
[[ -f ./test.img ]] && time rm ./test.img && sync -f

関連情報