【发布时间】:2010-09-16 05:03:21
【问题描述】:
我想创建一个稀疏文件,这样在我向它们写入数据之前,全零块不会占用实际磁盘空间。有可能吗?
【问题讨论】:
-
我认为了解您为什么需要稀疏文件会很有帮助。
-
你的意思是稀疏磁盘映像吗?
标签: c macos filesystems
我想创建一个稀疏文件,这样在我向它们写入数据之前,全零块不会占用实际磁盘空间。有可能吗?
【问题讨论】:
标签: c macos filesystems
对于默认的 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 卷,支持稀疏文件,但已被删除。当前支持的文件系统都没有稀疏文件支持。
【讨论】:
getattrlist 获取该卷的ATTR_VOL_CAPABILITIES 属性组,然后检查VOL_CAP_FMT_SPARSE_FILES 功能。如前所述,HFS+不具有此功能,但 APFS 具有。
【讨论】:
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 进程中在(挂载的)稀疏磁盘映像中创建一个文件。
【讨论】:
hdiutil 私有框架,以便以编程方式附加 DMG 文件(表示自 HFS+ 分区以来的磁盘映像的文件)。我想知道您是否碰巧在 DiskImages 框架内挖掘了一点并寻找正确的方法?谢谢
如果您寻找 (fseek, ftruncate, ...) 到末尾,文件大小将增加而不分配块,直到您写入孔。但是没有办法创建一个自动将零块转换为孔的魔术文件。你必须自己做。
这可能有助于查看(OpenBSD cp 命令插入孔而不是写入零)。 patch
【讨论】:
如果你想要可移植性,最后的办法是编写你自己的访问函数,这样你就可以管理一个索引和一组块。
本质上,您管理单个文件,因为操作系统管理磁盘,保存文件中的块链、已分配/空闲块的位图等。
当然,这会导致非优化和较慢的访问,只有在节省空间的要求绝对关键并且您有足够的时间编写一组强大的访问函数时,我才会推荐这种方法。
即使在这种情况下,我也会首先调查您的问题是否需要其他解决方案。也许您应该以不同的方式存储数据?
【讨论】:
看起来 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 文件系统)时,程序不会生成稀疏文件。
【讨论】: