データを書き込むまで、すべてゼロのブロックが実際のディスク領域を占有しないように、スパース ファイルを作成したいと考えています。出来ますか?
7 に答える
デフォルトのMacOSXファイルシステム(HFS +)がファイルの穴をサポートしているかどうかについては、多少の混乱があるようです。次のプログラムは、これが当てはまらないことを示しています。
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
void create_file_with_hole(void)
{
int fd = open("file.hole", O_WRONLY|O_TRUNC|O_CREAT, 0600);
write(fd, "Hello", 5);
lseek(fd, 99988, SEEK_CUR); // Make a hole
write(fd, "Goodbye", 7);
close(fd);
}
void create_file_without_hole(void)
{
int fd = open("file.nohole", O_WRONLY|O_TRUNC|O_CREAT, 0600);
write(fd, "Hello", 5);
char buf[99988];
memset(buf, 'a', 99988);
write(fd, buf, 99988); // Write lots of bytes
write(fd, "Goodbye", 7);
close(fd);
}
int main()
{
create_file_with_hole();
create_file_without_hole();
return 0;
}
プログラムは2つのファイルを作成します。各ファイルの長さは100,000バイトで、そのうちの1つには99,988バイトの穴があります。
HFS+パーティション上のMacOSX 10.5では、両方のファイルが同じ数のディスクブロック(200)を使用します。
$ ls -ls
total 400
200 -rw------- 1 user staff 100000 Oct 10 13:48 file.hole
200 -rw------- 1 user staff 100000 Oct 10 13:48 file.nohole
CentOS 5では、穴のないファイルは他のファイルより88多いディスクブロックを消費します。
$ ls -ls
total 136
24 -rw------- 1 user nobody 100000 Oct 10 13:46 file.hole
112 -rw------- 1 user nobody 100000 Oct 10 13:46 file.nohole
他の Unix と同様に、これはファイルシステムの機能です。ファイルシステムがすべてのファイルに対してそれをサポートしているか、サポートしていないかのどちらかです。Win32 とは異なり、それを実現するために特別なことをする必要はありません。また、Win32 とは異なり、スパース ファイルを使用してもパフォーマンスが低下することはありません。
MacOS では、デフォルトのファイルシステムはスパース ファイルをサポートしないHFS+ です。
更新: MacOS はスパース ファイルをサポートする UFS ボリュームをサポートしていましたが、削除されました。現在サポートされているファイルシステムはどれも、スパース ファイルをサポートしていません。
このスレッドは、スパース ファイルに関する包括的な情報源になります。Win32 の欠落部分は次のとおりです。
よろしく
最後までシーク (fseek、ftruncate、...) すると、穴に書き込むまでブロックが割り当てられずにファイル サイズが増加します。しかし、ゼロのブロックを穴に自動的に変換する魔法のファイルを作成する方法はありません。あなたはそれを自分でしなければなりません。
これは参考になるかもしれません (OpenBSD の cp コマンドは、ゼロを書き込む代わりに穴を挿入します)。 パッチ
hdiutil はスパース イメージとファイルを処理できますが、残念ながら、リンク先のフレームワークは非公開です。
以下の DiskImages フレームワークで定義されているように外部シンボルを定義することもできますが、これはプロダクション コードでは受け入れられない可能性が高く、フレームワークはプライベートであるため、ユース ケースをリバース エンジニアリングする必要があります。
cristi:~ diciu$ otool -L /usr/bin/hdiutil
/usr/bin/hdiutil: /System/Library/PrivateFrameworks/DiskImages.framework/Versions/A/DiskImages (互換バージョン 1.0.8、現在のバージョン 194.0.0) [..]
cristi:~ diciu$ nm /System/Library/PrivateFrameworks/DiskImages.framework/Versions/A/DiskImages | awk -F' ' '{print $3}' | c++フィルター | grep -i スパース
[..]
CSparseFile::sector2Band(長い長い)
CSparseFile::addIndexNode()
CSparseFile::readIndexNode(long long, SparseFileIndexNode*)
CSparseFile::readHeaderNode(CBackingStore*, SparseFileHeaderNode*, unsigned long)
[...簡潔にするためにカット]
後で編集
hdiutil を外部プロセスとして使用して、スパース ディスク イメージを作成することができます。C プロセスから、(マウントされた) スパース ディスク イメージにファイルを作成します。
OS X は UDF ボリューム上のスパース ファイルをサポートしているようです。OS X 10.9 で titaniumdecoy のテスト プログラムを試してみたところ、UDF ディスク イメージにスパース ファイルが生成されました。また、OS X で UFS がサポートされなくなったわけではないため、スパース ファイルが必要な場合、それらをサポートするネイティブでサポートされているファイル システムは UDF だけです。
SMB共有でもプログラムを試しました。サーバーが Ubuntu (ext4 ファイルシステム) の場合、プログラムはスパース ファイルを作成しますが、SMB を介した「ls -ls」ではそれが表示されません。Ubuntu ホスト自体で「ls -ls」を実行すると、ファイルがスパースであることが示されます。サーバーが Windows XP (NTFS ファイルシステム) の場合、プログラムはスパース ファイルを生成しません。
移植性が必要な場合の最後の手段は、独自のアクセス関数を作成して、インデックスとブロックのセットを管理することです。
本質的に、OS がファイルの一部であるブロックのチェーン、割り当て済み/空きブロックのビットマップなどを保持するディスクを管理するため、単一のファイルを管理します。
もちろん、これは最適化されていない低速のアクセスにつながります。スペースを節約する必要性が絶対に重要であり、堅牢なアクセス関数のセットを作成するのに十分な時間がある場合にのみ、このアプローチをお勧めします。
その場合でも、問題に別の解決策が必要かどうかを最初に調査します。おそらく、データを別の方法で保存する必要がありますか?