【问题标题】:Reading a large file using C (greater than 4GB) using read function, causing problems使用读取功能使用C(大于4GB)读取大文件,导致问题
【发布时间】:2023-03-17 06:15:02
【问题描述】:

我必须编写 C 代码来读取大文件。代码如下:

int read_from_file_open(char *filename,long size)
{
    long read1=0;
    int result=1;
    int fd;
    int check=0;
    long *buffer=(long*) malloc(size * sizeof(int));
    fd = open(filename, O_RDONLY|O_LARGEFILE);
    if (fd == -1)
    {
       printf("\nFile Open Unsuccessful\n");
       exit (0);;
    }
    long chunk=0;
    lseek(fd,0,SEEK_SET);
    printf("\nCurrent Position%d\n",lseek(fd,size,SEEK_SET));
    while ( chunk < size )
    {
        printf ("the size of chunk read is  %d\n",chunk);
        if ( read(fd,buffer,1048576) == -1 )
        {
            result=0;
        }
        if (result == 0)
        {
            printf("\nRead Unsuccessful\n");
            close(fd);
            return(result);
        }

        chunk=chunk+1048576;
        lseek(fd,chunk,SEEK_SET);
        free(buffer);
    }

    printf("\nRead Successful\n");

    close(fd);
    return(result);
}

我这里面临的问题是,只要传递的参数(大小参数)小于264000000字节,似乎就可以读取。随着每个循环,我的块变量的大小都在增加。

当我通过264000000字节或更多时,读取失败,即:根据检查使用读取返回-1。

谁能指出为什么会这样?我在正常模式下使用 cc 编译,而不是使用 DD64。

【问题讨论】:

  • 我可以看到您的代码存在一些严重问题。首先,您分配一个要读入的缓冲区,使用size 作为大小。然后,您使用固定大小读取缓冲区的信息,而不管您读入的缓冲区的分配大小。想想如果size 小于 250k 会发生什么。其次,由于文件是新打开的,因此您无需寻找开头。第三,你然后寻找size,但是size是文件中的记录数还是字节数?在分配缓冲区时,您使用 size 的方式不同。
  • 第四,释放循环内的缓冲区,但不要分配新的缓冲区。这意味着在第二次迭代中,它将读入未分配的内存。五、调用read会自动推进文件中的位置,不需要每次都去寻找。第六,当您阅读时检查错误,但不检查文件结尾。 read 在文件末尾返回 0
  • 最后,在读取大文件时,您不应该使用read。使用例如mmap 可能是更有效的解决方案,尤其是在您按顺序读取文件的情况下。
  • 同意使用 mmap 读取大文件的建议。此外,还应考虑增加分页或交换内存大小,以避免内存分配错误。

标签: c unix file-io posix


【解决方案1】:

首先,为什么您的周期中需要lseek()read() 将使光标在文件中前进读取的字节数。

而且,对于主题:long 和 chunk 的最大值分别为 2147483647,任何大于该值的数字实际上都会变为负数。

您想使用off_t 声明块:off_t chunk,大小为size_t。 这就是 lseek() 失败的主要原因。

再说一次,正如其他人所注意到的,你不想在循环中 free() 你的缓冲区。

另请注意,您将覆盖已读取的数据。 此外,read() 不一定会像您要求的那样读取,因此最好按照实际读取的字节数而不是您要读取的字节数来推进块。

综合考虑,正确的代码应该如下所示:

// Edited: note comments after the code
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif

int read_from_file_open(char *filename,size_t size)
{
int fd;
long *buffer=(long*) malloc(size * sizeof(long));
fd = open(filename, O_RDONLY|O_LARGEFILE);
   if (fd == -1)
    {
       printf("\nFile Open Unsuccessful\n");
       exit (0);;
    }
off_t chunk=0;
lseek(fd,0,SEEK_SET);
printf("\nCurrent Position%d\n",lseek(fd,size,SEEK_SET));
while ( chunk < size )
  {
   printf ("the size of chunk read is  %d\n",chunk);
   size_t readnow;
   readnow=read(fd,((char *)buffer)+chunk,1048576);
   if (readnow < 0 )
     {
        printf("\nRead Unsuccessful\n");
        free (buffer);
        close (fd);
        return 0;
     }

   chunk=chunk+readnow;
  }

printf("\nRead Successful\n");

free(buffer);
close(fd);
return 1;

}

我还冒昧地删除了结果变量和所有相关逻辑,因为我相信它可以被简化。

编辑:我注意到某些系统(尤其是 BSD)没有O_LARGEFILE,因为那里不需要它。因此,我在开头添加了一个#ifdef,这将使代码更具可移植性。

【讨论】:

    【解决方案2】:

    lseek 函数可能难以支持大文件大小。尝试使用lseek64

    请查看链接查看使用lseek64函数时需要定义的相关宏。

    【讨论】:

      【解决方案3】:

      如果是 32 位机器,读取大于 4gb 的文件会导致一些问题。因此,如果您使用 gcc 编译器,请尝试使用宏 -D_LARGEFILE_SOURCE=1-D_FILE_OFFSET_BITS=64

      也请检查link

      如果您使用任何其他编译器,请检查类似类型的编译器选项。

      【讨论】:

        猜你喜欢
        • 2010-09-22
        • 1970-01-01
        • 2017-11-30
        • 1970-01-01
        • 2015-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-02
        相关资源
        最近更新 更多