我想创建一个稀疏文件,这样在我向它们写入数据之前,全零块不会占用实际的磁盘空间。是否可以?
7 回答
关于默认的 Mac OS X 文件系统 (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;
}
该程序创建了两个文件,每个文件的长度为 100,000 字节,其中一个有一个 99,988 字节的孔。
在 HFS+ 分区上的 Mac OS X 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 卷,但已被删除。当前支持的文件系统都没有稀疏文件支持。
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' ''{打印 $3}' | c++过滤器| grep -i 稀疏
[..]
CSparseFile::sector2Band(long long)
CSparseFile::addIndexNode()
CSparseFile::readIndexNode(long long, SparseFileIndexNode*)
CSparseFile::readHeaderNode(CBackingStore*, SparseFileHeaderNode*, unsigned long)
[...为简洁起见]
稍后编辑
您可以将 hdiutil 用作外部进程并让它为您创建一个稀疏磁盘映像。然后,您将在 C 进程中在(已挂载的)稀疏磁盘映像中创建一个文件。
如果您寻求 (fseek, ftruncate, ...) 到最后,文件大小将增加而不分配块,直到您写入孔。但是没有办法创建一个自动将零块转换为孔的魔术文件。你必须自己做。
这可能有助于查看(OpenBSD cp 命令插入孔而不是写入零)。 修补
如果你想要可移植性,最后的手段是编写你自己的访问函数,这样你就可以管理一个索引和一组块。
本质上,您管理单个文件,因为操作系统管理磁盘,保留作为文件一部分的块链、已分配/空闲块的位图等。
当然这会导致非优化和较慢的访问,只有在节省空间的要求绝对关键并且您有足够的时间编写一组强大的访问函数时,我才会推荐这种方法。
即使在这种情况下,我也会首先调查您的问题是否需要不同的解决方案。也许您应该以不同的方式存储数据?
看起来 OS X 支持 UDF 卷上的稀疏文件。我在 OS X 10.9 上尝试了 Titandecoy 的测试程序,它确实在 UDF 磁盘映像上生成了一个稀疏文件。此外,并不是说 OS X 不再支持 UFS,所以如果您需要稀疏文件,UDF 是唯一支持它们的本机支持的文件系统。
我还尝试了有关 SMB 共享的程序。当服务器是 Ubuntu(ext4 文件系统)时,程序会创建一个稀疏文件,但通过 SMB 的“ls -ls”不会显示该文件。如果您在 Ubuntu 主机本身上执行“ls -ls”,它确实显示文件是稀疏的。当服务器是 Windows XP(NTFS 文件系统)时,程序不会生成稀疏文件。