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);
}
参数 arrayToFill
是 void**
类型,因为锻炼目标。每个函数都必须对泛型类型执行,并且数组可能会填充各种类型的数据(在这个例子中,巨大的数字,但它可能包含巨大的字符串、整数等等......)。
我不明白为什么我要调用 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);
}
我正在尝试读取一个包含 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);
}
参数 arrayToFill
是 void**
类型,因为锻炼目标。每个函数都必须对泛型类型执行,并且数组可能会填充各种类型的数据(在这个例子中,巨大的数字,但它可能包含巨大的字符串、整数等等......)。
我不明白为什么我要调用 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);
}