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

来源:互联网 发布:java src 文件路径 编辑:程序博客网 时间:2024/04/19 18:01
以下的做法整理自论坛上的帖子。 


如何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
0 0
原创粉丝点击