您的位置:首页 > 运维架构 > Linux

Linux 下 C语言大文件读写(大于4G)

2016-02-18 16:26 330 查看
以下的做法整理自论坛上的帖子。

如何create大文件

要大就非常大,1T吧。

有两种方法:

一.dd

dd if=/dev/zero of=1T.img bs=1G seek=1024 count=0

bs=1G表示每一次读写1G数据,count=0表示读写0次,seek=1024表示略过1024个Block不写,前面blocksize是1G,所以共略过1T!

这是创建大型sparse文件最简单的方法。

二.ftruncate64/ftruncate

如果用系统函数就稍微有些麻烦,因为涉及到宏的问题。我会结合一个实际例子详细说明,其中OPTION标志的就是测试项。

文件sparse.c:

//OPTION 1:是否定义与大文件相关的宏

#define _LARGEFILE_SOURCE

#define _LARGEFILE64_SOURCE

#define _FILE_OFFSET_BITS 64

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <errno.h>

#include <string.h>

#define FILENAME "bigfile"

#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

int main(int argc, char **argv)

{

int fd, ret;

off_t offset;

int total = 0;

if ( argc >= 2 )

{

total = atol(argv[1]);

printf("total=%d/n", total);

}

//OPTION 2:是否有O_LARGEFILE选项

//fd = open(FILENAME,O_RDWR|O_CREAT|O_LARGEFILE, 0644);

fd = open(FILENAME, O_RDWR|O_CREAT, 0644);

if (fd < 0) {

perror(FILENAME);

return -1;

}

offset = (off_t)total*1024ll*1024ll*1024ll;

printf("offset=%ld/n", offset);

//OPTION 3:是否调用64位系统函数

//if (ftruncate64(fd, offset) <0)

if (ftruncate(fd, offset) <0)

{

printf("[%d]-ftruncate64 error: %s/n", errno,strerror(errno));

close(fd);

return 0;

}

close(fd);

printf("OK/n");

return 0;

}

测试环境:

linux:/disk/test/big # gcc --version

gcc (GCC) 3.3.5 20050117 (prerelease) (SUSE Linux)

linux:/disk/test/big # uname -a

Linux linux 2.6.11.4-20a-default #1 Wed Mar 23 21:52:37 UTC 2005i686 i686 i386 GNU/Linux

测试结果(伪码表示):

1.宏定义完全的情况下:

IF {O_LARGEFILE=TRUE &&ftruncate64=TRUE}

OK;

ELSEIF {O_LARGEFILE=FALSE &&ftruncate64=TRUE}

OK;

ELSEIF {O_LARGEFILE=FALSE &&ftruncate64=FALSE}

运行不报错,但是不支持>4G;

ELSEIF {O_LARGEFILE=TRUE &&ftruncate64=FALSE}

运行不报错,但是不支持>4G;

【结论】:在宏定义完全的情况下,是否调用ftruncate64,是决定支持4G以上文件的关键,O_LARGEFILE无作用。

2.宏定义不完全:缺少_FILE_OFFSET_BITS

首先声明一点,O_LARGEFILE需要定义_LARGEFILE64_SOURCE。

IF {O_LARGEFILE=TRUE &&ftruncate64=TRUE}

产生不正常超大文件;

ELSEIF {O_LARGEFILE=FALSE &&ftruncate64=TRUE}

产生不正常超大文件;

ELSEIF {O_LARGEFILE=FALSE &&ftruncate64=FALSE}

运行不报错,但是不支持>2G;

ELSEIF {O_LARGEFILE=TRUE &&ftruncate64=FALSE}

运行不报错,但是不支持>4G;

【结论】:未定义_FILE_OFFSET_BITS的情况下,ftruncate64调用是非法的,会产生无法预料的后果,这里的测试就是产生一个超大文件(>1T),我也无法解释其原因;O_LARGEFILE的作用就是在32位系统中支持大文件系统,允许打开那些用31位(2G)都不能表示其长度的大文件;此外,off_t为unsignedint类型,也就是说最多只能达到4G,所以ftruncate最大支持4G文件。

总结一下:如果要支持超过2G的文件,至少需要定义_LARGEFILE64_SOURCE宏,并且设置O_LARGEFILE选项;如果要支持超过4G,需要定义所有上述的宏,并且调用ftruncate64;其余的搭配都是错误的!

【附】:

dd 的主要选项:

指定数字的地方若以下列字符结尾乘以相应的数字:

b=512, c=1, k=1024, w=2, m=1024k, g=1024m

大小写不限。

if=file

输入文件名,缺省为标准输入。

of=file

输出文件名,缺省为标准输出。

ibs=bytes

一次读入 bytes 个字节(即一个块大小为 bytes 个字节)。

obs=bytes

一次写 bytes 个字节(即一个块大小为 bytes 个字节)。

bs=bytes

同时设置读写块的大小为 bytes ,可代替 ibs 和 obs 。

cbs=bytes

一次转换 bytes 个字节,即转换缓冲区大小。

skip=blocks

从输入文件开头跳过 blocks 个块后再开始复制。

seek=blocks

从输出文件开头跳过 blocks 个块后再开始复制。(通常只有当输出文件是磁盘或磁带时才有效)

count=blocks

仅拷贝 blocks 个块,块大小等于 ibs 指定的字节数。

conv=conversion[,conversion...]

用指定的参数转换文件。

转换参数:

ascii 转换 EBCDIC 为 ASCII。

ebcdic 转换 ASCII 为 EBCDIC。

ibm 转换 ASCII 为 alternate EBCDIC.

block 把每一行转换为长度为 cbs 的记录,不足部分用空格填充。

unblock

使每一行的长度都为 cbs ,不足部分用空格填充。

lcase 把大写字符转换为小写字符。

ucase 把小写字符转换为大写字符。

noerror

不显示错误

notrunc

不截短输出文件。

sync 把每个输入块填充到ibs个字节,不足部分用空(NUL)字符补齐。

本文转自:
http://blog.sina.com.cn/s/blog_5c93b2ab0100vhk1.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: