C读取20000000行文件的有效方法

C efficient way to read a file of 20000000 lines

我正在尝试读取一个包含 2000 万行的庞大数据集,每一行中都有一个巨大的数字(实际上我将数字存储在 unsigned long long 变量中),例如:1774251443, 8453058335, 19672843924,等等...

我开发了一个简单的函数来执行此操作,我将在下面展示

void read(char pathToDataset[], void **arrayToFill, int arrayLength) {
    FILE *dataset = fopen(pathToDataset, "r");
    if (dataset == NULL ) {
        printf("Error while opening the file.\n");
        exit(0); // exit failure, it closes the program
    }

    int i = 0;

    /* Prof. suggestion: do a  malloc RIGHT HERE, for allocate a 
     * space in memory in which store the element
     * to insert in the array
     */

    while (i < arrayLength && fscanf(dataset, "%llu", (unsigned long long *)&arrayToFill[i]) != EOF) {

        // ONLY FOR DEBUG, it will print 
        //printf("line: %d.\n", i);  20ML of lines!

        /* Prof. suggestion: do another malloc here, 
         * for each element to be read. 
         */

        i++;
    }

    printf("Read %d lines", i);
    fclose(dataset);
}

参数 arrayToFillvoid** 类型,因为锻炼目标。每个函数都必须对泛型类型执行,并且数组可能会填充各种类型的数据(在这个例子中,巨大的数字,但它可能包含巨大的字符串、整数等等......)。

我不明白为什么我要调用 2 个 malloc 调用,一个调用不够吗?

对于你的第一个问题,将 malloc 视为对存储 N 个对象的内存调用,所有对象的大小都是 S。当你有参数 void ** arrayToFill, int arrayLength 时,你是说这个数组将包含 arrayLength 数量的 个大小为 sizeof(void*) 的指针。那就是第一次分配和调用malloc。

但是该数组的 成员 是指针,用于保存数组或本质上是其他对象本身的内存。第一次调用 malloc 只分配内存来存储每个数组成员的 void*,但数组的每个单独成员的内存需要它自己的 malloc() 调用。

高效读行

对于你的另一个问题,进行大量小的内存分配,然后释放它们(假设你会这样做,否则你会泄漏大量内存)非常慢。但是,I/O 相关任务的性能影响更多地取决于调用次数,而不是分配的 内存量

让您的程序将整个文件读入内存,并为 2000 万或您希望处理的任意整数分配一个 unsigned long long 数组。这样,您可以解析文件内容,使用 <stdlib.h> 中的 strtol 函数,并将结果 long 一个一个地复制到您的大数组中。

这样,您只需使用 2-3 次大内存分配和释放。

我想到了这个 POSIX 解决方案,看看它是否有帮助

#include <unistd.h> //for read, write, lseek
#include <stdio.h> //fprintf
#include <fcntl.h> //for open
#include <string.h> //
#include <stdlib.h> // for exit and define
#include <sys/types.h>
#include <sys/stat.h>

int main(int argc, char * argv[])
{
  int fd; // file descriptor
  char * buffer; //pointer for the malloc

  if(argc < 2)
  {
    fprintf(stderr, "Insert the file name as parameter\n");
    exit(EXIT_FAILURE);
  }

if((fd =  open(argv[1], O_RDONLY)) == -1)// opens the file in read-only mode
{
  fprintf(stderr, "Can't open file\n");
  exit(EXIT_FAILURE);
}


off_t bytes = lseek(fd, 0, SEEK_END); // looks at how many bytes the file has
              lseek(fd, 0, SEEK_SET); // returns the file pointer to the start position

buffer = malloc(sizeof(char)*bytes); // allocates enough memory for reading the file

int r = read(fd, buffer, bytes); //reads the file

if(r == -1)
{
  fprintf(stdout, "Error reading\n");
  exit(EXIT_FAILURE);
}

fprintf(stdout, "\n%s", buffer); // prints the file

close(fd);
exit(EXIT_SUCCESS);

}