zl程序教程

您现在的位置是:首页 >  后端

当前栏目

C语言之lseek64报Invalid argument根本原因(六十八)

C语言invalid argument
2023-09-14 09:09:58 时间
计算机常用的存储单位: 
8 bit = 1 Byte 一字节;
1024B=1KB (KiloByte) 千字节;
1024KB=1MB(MegaByte)兆字节;
1024MB=1GB(GigaByte)吉字节;
1024GB=1TB(TeraByte)太字节;
1024TB=1PB(PetaByte)拍字节;
1024PB=1EB(ExaByte)艾字节;
1024EB=1ZB(ZetaByte)泽字节;
1024ZB=1YB(YottaByte)尧字节;
1024YB=1BB(Brontobyte)珀字节;
1024BB=1 NB(NonaByte) 诺字节;
1024NB=1DB(DoggaByte)刀字节。

1.在32位系统中,open()和lseek()只能打开/位移数据最大为4GB问题

例如创建/访问超过4GB以上需要使用几种方式

  • open()使用O_LARGEFILE宏

open(argv[1], O_WRONLY | O_CREAT | O_LARGEFILE, 0755);

添加头文件:

//1.lseek64()
//#define _GNU_SOURCE /* for O_DIRECT */

//Or: 
//2.lseek64()
#define __USE_FILE_OFFSET64
#define __USE_LARGEFILE64
#define _LARGEFILE64_SOURCE
  • 使用fopen64()函数

同样添加头文件

//1.lseek64()
//#define _GNU_SOURCE /* for O_DIRECT */

//Or: 
//2.lseek64()
#define __USE_FILE_OFFSET64
#define __USE_LARGEFILE64
#define _LARGEFILE64_SOURCE

2.创建一个超过4GB以上的空文件sample

理论上可以最大创建2^63-1(184467440TB)大小的文件,但是电脑硬盘目前还达不到,集群的话恐怕也难以达到这么大的空间。

如果传入的是(1ull<<63) - 1,系统会报错:lseek: Invalid argument(无效参数),因为它远远目前硬盘的所承受的大小,所以传入lseek64()函数的offset太大了,甚至达到几百TB,远远超出一般硬盘的容量,所以报无效参数,这才是根本原因,如果传入的很大的参数说明,传入的参数是有问题的。

如下创建大文件的demo:

#define _LARGEFILE64_SOURCE

#include<stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char** argv){
  if(argc < 2){
    printf("Usage: %s [file]\n", argv[0]);
    return -1;
  }
  int fd = open(argv[1], O_WRONLY | O_CREAT | O_LARGEFILE, 0755);
  printf("2^63 -1 = %lld\n",(1ULL << 43) - 1); //9223372036854775807
  printf("2^64 -1 = %llu\n",(1ULL << 64) - 1);//18446744073709551615 = 184467440TB = 184467PB = 184EB

  
  //理论上可以最大创建2^63-1(184467440TB)大小的文件,但是电脑硬盘目前还达不到,集群的话恐怕也难以达到这么大的空间,如果传入的是(1ull<<63) - 1,系统会报错:lseek: Invalid argument(无效参数),因为它远远目前硬盘的所承受的大小.
  off_t ret = lseek64(fd, (1ull<<43) - 1, SEEK_SET); //8796093022207 = 8TB //ok
  //off_t ret = lseek64(fd, (1ull<<8) - 1, SEEK_SET); //0xFFFFFFFFL = 4GB
  if(ret == -1){
    perror("lseek");
    return -1;
  }
  write(fd, "\0", 1);
  close(fd);
        
  return 0;
}

查看创建成功的空文件

 # ls -alh 222.txt 
-rwxr-xr-x 1  8.0T  2月 16 00:52 222.txt

注意:我的电脑是4TB,但是却能创建成功的8TB大小的文件,也是不可思议。

但是如果再传入lseek64(fd, (1ull<<44) - 1, SEEK_SET); 就报无效参数。