我有一个C写的程序。它计算一些东西并将输出写入文件。我的问题是它写的不超过2GB。我来写一个简化的代码。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <malloc.h>
#include <errno.h>
int main() {
size_t size = 3221225472LL;
char *map = malloc(size);
size_t allocated = malloc_usable_size(map);
int fd = open("myfile", O_RDWR|O_CREAT|O_TRUNC, (mode_t)0644);
ssize_t written = write(fd, map, size);
return 0;
}
尽管正在创建输出文件“myfile”,但无论我请求的大小是否大于2GB,其大小始终为2GB(2147479552字节)。malloc()
成功分配了请求大小的内存(在本例中,“分配”为3GB)。write()
之后的errno
为0。
环境如下
- OS:Ubuntu 16.04.1 x86_64
- 物理内存大小:32GB
- 文件系统:ext4
编译:
gcc code.c -D_FILE_OFFSET_BITS=64 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
这可能是什么原因呢?
添加:
在得到两个响应后,我添加了重试代码如下:
int main() {
size_t size = 3221225472LL;
char *map = malloc(size);
size_t allocated = malloc_usable_size(map);
int fd = open("myfile", O_RDWR|O_CREAT|O_TRUNC, (mode_t)0644);
ssize_t written = write(fd, map, size);
while (written < size) {
written += write(fd, &map[written], size-written);
}
return 0;
}
2条答案
按热度按时间vh0rcniy1#
根据man page(强调我的)
在Linux上,
write()
(和类似的系统调用)将传输 * 最多0x7ffff000(2,147,479,552)字节 *,返回实际传输的字节数。(在32位和64位系统上都是如此。)cgh8pdjw2#
一些文件系统对文件大小有很强的限制,特别是FAT32。disk quotas和资源限制(参见
RLIMIT_FSIZE
的setrlimit(2))都限制了文件大小(当然还有文件系统本身的可用空间)。顺便说一句,你的
written
很可能(在你调用write(2)之后...)只有231。你应该检查一下。和write(2)文档:
在Linux上,write()(和类似的系统调用)最多传输0x 7 ffff 000(2,147,479,552)字节,返回实际传输的字节数。(在32位和64位系统上都是如此。)
当然,对write(2)的给定调用永远不应该被期望已经写入了所有需要的字节(在所有POSIX系统上都是如此,在20世纪80年代的Unix系统上也是如此)。例如,一个
write
到某个pipe(7)肯定无法写入那么多字节。顺便说一句,对write(2)的一个巨大的单次调用可能(或者至少可能)比使用较小缓冲区的几个调用效率更低。最佳缓冲区大小是特定于实现的(也与page cache和硬件有关),但可能是几十KB,或最多1 MB。
您可能更喜欢使用
<stdio.h>
bufferedfwrite(3),但您应该检查返回的计数。最后,您可以考虑在您的案例中使用mmap(2)。参见msync(2)
请注意,对于大型文件,真实的的瓶颈是硬件(磁盘本身)。因此,使用缓冲的
fwrite
来提高性能并不重要。(you在注解中提到TB文件)
顺便说一句,对于大的TB数据集,使用一些更高级别的方法(特别是数据库,可能是sqlite,或者索引文件à la GDBM)实际上可能更有效,因为这样你就只能写数据的一部分(或者因为RDBMS运行在远程数据库服务器上,例如,RDBMS)。使用MariaDB或PostGreSQL)。但是硬件带宽小于千兆字节/秒,所以写入一个兆字节可能需要几个小时。即使交换容量很大,如果没有thrashing,在32 GB的机器上也无法传输
malloc
一TB。您还可以巧妙地使用posix_fadvise(2)来略微提高性能(但不是很多:对于TB级文件,瓶颈是硬件)