linux环境下操作特大文件

今天遇到一个问题,程序写文件到2g时候报错退出:ファイルサイズ制限を超過しました

linux环境下操作特大文件,需要在编译时加上-D _FILE_OFFSET_BITS=64定义宏

标准库竟然不支持大文件操作,但是系统是支持的

因为在32位机器下,默认情况下,文件长度是off_t类型,这个可以从ftrucate的参数,从stat获取的文件属性struct stat中都可以看出文件的长度是用off_t类型表示的,即文件的长度在32位机器下默认是long int类型。 所以,默认情况下,在Linux系统下,fopen和open操作的文件大小不能超过2G。

还有一种方法,使用宏定义#define _FILE_OFFSET_BITS 64(要注意的是,#define必须放在#include <unistd.h>之前)和Linux自己的库函数——open,使用O_LARGEFILE属性,open("./bill_test",O_LARGEFILE|O_APPEND|O_RDWR,0666);

或者用LSEEK64(fd, (unsigned long long)offset, SEEK_SET)定位偏移量

因为fseek (FILE *stream, longoffset, int whence)和

long ftell(FILE *stream) 不能访问4G以上文件

此时要用 fseeko (FILE *stream, off_toffset, int whence)

off_t ftello(FILE *stream);代替

为什么会产生大文件的限制又为什么这样解决它?

C标准库中的ftell函数的返回值为 long类型,在主流的GCC等编译器中对long类型变量分配的大小为4个字节,即32位。也就是说可操作的文件大小至多是(2^31-1)B

在linux 下,我们可以使用lseek系统调用(不要用C标准库中的fseek(),因为fseek也只支持32位)。lseek函数的原型可在 /usr/include/unistd.h 中查看(unistd.h只是使用extern对lseek函数进行声明,真正定义的位置在内核源码中)。用户态使用的lseek接口是:

off_t lseek(int fd, off_t offset, int whence);

在/usr/include中查找off_t类型的定义可以看出,off_t其实拥有两种类型:__off_t和__off64_t

要使 off_t为__off64_t类型,必须#define __USE_FILE_OFFSET64.

grep __USE_FILE_OFFSET64 /usr/include/* -r。 在<sys/types.h>找到了这个:

#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64
# define __USE_FILE_OFFSET64    1
#endif

这样就可以64位偏移地址形式操作文件。文件最大为(2^63-1)B

可以使用dd来制造文件:dd if=/dev/zero of=output bs=10M count=2400
除去这个限制,ext3对文件的限制又如何呢?

因为ext3的inode使用32的地址指针以及3次间接指针,这样单个文件的大小最多为2^10*2^10*2^10*2^11,也就是2的41次方,即在32系统上并使用4k块大小时,单个文件最多是8TB。由于使用32位的地址长度,ext3最多支持的磁盘大小为2^31*4K,即8TB(inode号是有符号int的变量,所以是2^31)。
   由于当今磁盘阵列的发展,已经出现了超过8TB的磁盘阵列,于是最近内核邮件列表里火了一把关于ext3扩展的讨论,这就是ext4。
 

posted @ 2012-06-21 10:17  天天hime  阅读(2737)  评论(0)    收藏  举报