最后一次更新:我同学用fread()
把整个文件的三分之一读取成一个字符串,这样可以避免内存不足。然后处理这个字符串,将这个字符串分离到你的数据结构中。注意,你需要关心一个问题:在这个字符串的末尾,最后这几个字符可能不能组成一个整数。考虑一种检测这种情况的方法,以便您可以将这些字符与下一个字符串的前几个字符连接起来。
每个数字对应于数据结构中的不同变量。您的数据结构应该非常简单,因为每次将数据插入一个数据结构时,速度都非常慢。大部分时间花在将数据插入数据结构上。因此,处理这些数据最快的方法是:用fread()
把这个文件读成一个字符串,把这个字符串分成不同的一维数组。
例如(只是一个例子,不是来 self 的项目),我有一个文本文件,如:
72 24 20
22 14 30
23 35 40
42 29 50
19 22 60
18 64 70
.
.
.
每一行是一个人的信息。第一栏是这个人的年龄,第二栏是他的存款,第二栏是他妻子的年龄。
然后我们使用fread()
将这个文本文件读入字符串,然后我使用stroke()
来分离它(你可以使用更快的方法来分离它)。
不要使用数据结构来存储分离的数据!
我的意思是,不要这样做:
struct person
{
int age;
int deposit;
int wife_age;
};
struct person *my_data_store;
my_data_store=malloc(sizeof(struct person)*length_of_this_array);
//then insert separated data into my_data_store
不要用数据结构来存储数据! 存储数据的最快方式是这样的:
int *age;
int *deposit;
int *wife_age;
age=(int*)malloc(sizeof(int)*age_array_length);
deposit=(int*)malloc(sizeof(int)*deposit_array_length);
wife_age=(int*)malloc(sizeof(int)*wife_array_length);
// the value of age_array_length,deposit_array_length and wife_array_length will be known by using `wc -l`.You can use wc -l to get the value in your C program
// then you can insert separated data into these arrays when you use `stroke()` to separate them.
第二次更新:最好的方法是使用freed()
将文件的一部分读入一个字符串,然后将这些字符串分离到你的数据结构中。顺便说一下,不要使用任何可以将字符串格式化为整数的标准库函数,那样会很慢,比如 fscanf() 或 atoi()
,我们应该编写自己的函数来将字符串转换为n 整数。不仅如此,我们还应该设计一个更简单的数据结构来存储这些数据。顺便说一句,我同学可以在7秒内读完这个1.7G的文件。有一种方法可以做到这一点。这种方式比使用多线程要好得多。我没有看到他的代码,看到他的代码后,我会第三次更新告诉你你怎么会这样。那将是我们类(class)结束两个月后。
更新:我用多线程来解决这个问题!!有用!注意:使用多线程时不要使用clock()来计算时间,所以我认为执行时间会增加。
我想澄清的一件事是,读取文件而不将值存储到我的结构中的时间大约为 20 秒。将值存储到我的结构中的时间约为 60 秒。 “读取文件时间”的定义包括读取整个文件并将值存储到我的结构中的时间。读取文件的时间=扫描文件+将值存储到我的结构中。因此,有一些更快储值的建议吗? (顺便说一句,我无法控制inout文件,它是我们教授生成的。我正在尝试使用多线程来解决这个问题,如果可行,我会告诉你结果。)
我有一个文件,大小是1.7G。 看起来像:
1 1427826
1 1427827
1 1750238
1 2
2 3
2 4
3 5
3 6
10 7
11 794106
.
.
继续。
它在文件中有大约一千万行。现在我需要读取这个文件并在 15 秒内将这些数字存储在我的数据结构中。
我曾尝试使用 freed()
来读取整个文件,然后使用 strtok()
来分隔每个数字,但它仍然需要 80 秒。如果我使用 fscanf()
,它会更慢。我该如何加快速度?也许我们不能让它少于 15 秒。但是80秒阅读它太长了。如何以最快的速度阅读它?
这是我阅读代码的一部分:
int Read_File(FILE *fd,int round)
{
clock_t start_read = clock();
int first,second;
first=0;
second=0;
fseek(fd,0,SEEK_END);
long int fileSize=ftell(fd);
fseek(fd,0,SEEK_SET);
char * buffer=(char *)malloc(sizeof(char)*fileSize);
char *string_first;
long int newFileSize=fread(buffer,1,fileSize,fd);
char *string_second;
while(string_first!=NULL)
{
first=atoi(string_first);
string_second=strtok(NULL," \t\n");
second=atoi(string_second);
string_first=strtok(NULL," \t\n");
max_num= first > max_num ? first : max_num ;
max_num= second > max_num ? second : max_num ;
root_level=first/NUM_OF_EACH_LEVEL;
leaf_addr=first%NUM_OF_EACH_LEVEL;
if(root_addr[root_level][leaf_addr].node_value!=first)
{
root_addr[root_level][leaf_addr].node_value=first;
root_addr[root_level][leaf_addr].head=(Neighbor *)malloc(sizeof(Neighbor));
root_addr[root_level][leaf_addr].tail=(Neighbor *)malloc(sizeof(Neighbor));
root_addr[root_level][leaf_addr].g_credit[0]=1;
root_addr[root_level][leaf_addr].head->neighbor_value=second;
root_addr[root_level][leaf_addr].head->next=NULL;
root_addr[root_level][leaf_addr].tail=root_addr[root_level][leaf_addr].head;
root_addr[root_level][leaf_addr].degree=1;
}
else
{
//insert its new neighbor
Neighbor *newNeighbor;
newNeighbor=(Neighbor*)malloc(sizeof(Neighbor));
newNeighbor->neighbor_value=second;
root_addr[root_level][leaf_addr].tail->next=newNeighbor;
root_addr[root_level][leaf_addr].tail=newNeighbor;
root_addr[root_level][leaf_addr].degree++;
}
root_level=second/NUM_OF_EACH_LEVEL;
leaf_addr=second%NUM_OF_EACH_LEVEL;
if(root_addr[root_level][leaf_addr].node_value!=second)
{
root_addr[root_level][leaf_addr].node_value=second;
root_addr[root_level][leaf_addr].head=(Neighbor *)malloc(sizeof(Neighbor));
root_addr[root_level][leaf_addr].tail=(Neighbor *)malloc(sizeof(Neighbor));
root_addr[root_level][leaf_addr].head->neighbor_value=first;
root_addr[root_level][leaf_addr].head->next=NULL;
root_addr[root_level][leaf_addr].tail=root_addr[root_level][leaf_addr].head;
root_addr[root_level][leaf_addr].degree=1;
root_addr[root_level][leaf_addr].g_credit[0]=1;
}
else
{
//insert its new neighbor
Neighbor *newNeighbor;
newNeighbor=(Neighbor*)malloc(sizeof(Neighbor));
newNeighbor->neighbor_value=first;
root_addr[root_level][leaf_addr].tail->next=newNeighbor;
root_addr[root_level][leaf_addr].tail=newNeighbor;
root_addr[root_level][leaf_addr].degree++;
}
}
最佳答案
一些建议:
a) 考虑将文件转换(或预处理)为二进制格式;目的是最小化文件大小并大大降低解析成本。我不知道您的值的范围,但是各种技术(例如使用一位来判断数字是小还是大并将数字存储为 7 位整数或 31 位整数)可以将文件减半IO(以及从磁盘读取文件的速度翻倍)并将解析成本降至几乎为零。 注意:为了获得最大效果,您首先要修改创建该文件的任何软件。
b) 在解析之前将整个文件读入内存是错误的。它使所需的 RAM 量(以及分配/释放的成本)加倍,并且对 CPU 缓存有不利影响。取而代之的是读取少量文件(例如 16 KiB)并处理它,然后读取下一 block 并处理它,依此类推;这样您就可以不断重复使用相同的小缓冲内存。
c) 对文件 IO 使用并行性。在处理文件的前一部分时读取文件的下一部分应该不难(通过使用 2 个线程或使用异步 IO)。
d) 为“邻居”结构预分配内存并从循环中删除大部分/所有 malloc()
调用。最好的情况是使用静态分配的数组作为池——例如Neighbor myPool[MAX_NEIGHBORS];
其中 malloc()
可以替换为 &myPool[nextEntry++];
。这减少/消除了 malloc()
的开销,同时还改进了数据本身的缓存局部性。
e) 使用并行来存储值。例如,您可以有多个线程,其中第一个线程处理 root_level % NUM_THREADS == 0
的所有情况,第二个线程处理 root_level % NUM_THREADS == 1
的所有情况> 等
有了以上所有(假设现代 4 核 CPU),我认为您可以将总时间(用于读取和存储)减少到 15 秒以内。
关于c - 如何快速读取和解析带有数字的文本文件(在 C 中)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29785412/