微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

打开并写入C中的多个文件

input是大约70GB的单个文件,其每一行包含客户信息。 一个程序读取这个文件并为每个客户端创build一个文件。 有8000个客户,但是我们必须为40000个客户提供服务。 目前,UNIXsorting命令用于按客户端对文件进行sorting,然后写入客户端文件。 这样程序只有一个文件处理程序打开来创build文件。 我们不想使用sorting命令,因为它消耗大约1.5个小时。 然而,这意味着打开的8000个文件处理程序将需要保持打开状态。 内核参数可能需要修改。 是否可以在不改变内核参数的情况下打开如此多的文件。 我尝试通过libevent网站,但不知道这是否是正确的解决scheme。

/ sys / kernel / debug / tracing / trace_marker错误文件描述符错误

指定文件描述符号码?

在Linux平台上使用套接字时是否有文件描述符泄漏?

有没有办法恢复/恢复nohup查看控制台中的输出

使用Windows API检索打开的文件描述符的数量

您不一定需要同时打开8000个文件句柄,也不需要对数据进行排序。 排序是一种浪费,除非您需要对每个客户行进行排序。

据推测,你可以通过线上的一些项目来识别客户。 假设(例如)每行中的前8个字符,那么你的伪代码如下所示:

delete all files matching "*_out.dat" for each line in file: key = left (line,8) open file key + "_out.dat" for append write line to file close file

而已。 简单。 一次只打开一个文件,没有时间浪费排序。

现在可以做出进一步的改进,其中包括

除非下一行有不同的键,否则不要关闭前一行的文件。 这将捕获在同一个键上有一百个记录的情况,并且在这种情况下将保持文件打开。

保持打开文件句柄的缓存像最近使用的列表(比如16个不同的键)。 同样,这将阻止关闭,直到文件句柄被重新使用,但它将很好地处理集群更有效的情况(例如客户1,2,3,7,1,3, 7,4,…)。

但基本理论是一样的:不要一下子打开8000(或40000)文件

或者,只处理数据,将其全部存储到数据库中,然后使用查询,然后使用一系列查询创建每个文件。 是否比上述解决方案快 ,应该进行测试,因为事实上应该在这里给出的每个建议。 措施,不要猜测!

现在,因为我已经调用了这个优化咒语,所以让我们来做一些时间安排,记住这是我的硬件特有的,可能与您的不同。

从下面的脚本开始,它会生成一个一百万行文件,其中每行的前八个字符是一个介于10000000和10032767之间的随机数。 我们将使用包括5到8个字符的字符给我们客户号码,每个客户大约一百条线上的一万个客户:

#!/bin/bash line='the quick brown fox jumps over the lazy dog' for p0 in 1 2 3 4 5 6 7 8 9 0 ; do for p1 in 1 2 3 4 5 6 7 8 9 0 ; do for p2 in 1 2 3 4 5 6 7 8 9 0 ; do for p3 in 1 2 3 4 5 6 7 8 9 0 ; do for p4 in 1 2 3 4 5 6 7 8 9 0 ; do for p5 in 1 2 3 4 5 6 7 8 9 0 ; do ((x = 10000000 + $RANDOM)) echo "$x$line" done done done done done done

产生的文件大小约为50M。 我们可以通过简单地将它的两个副本连接到另一个文件来扩展到100M,这给了我们每个客户大约两百行。

现在,检查以下程序:

#include <stdio.h> #include <string.h> #include <errno.h> #define FOUT_STR "1234_out.dat" int main (void) { FILE *fIn,*fOut; char outFile[sizeof (FOUT_STR)]; char buff[1000]; if ((fIn = fopen ("data.dat","r")) == NULL) { printf ("Error %d opening 'data.dat'n",errno); return 1; } memcpy (outFile,FOUT_STR,sizeof (FOUT_STR)); if ((fOut = fopen (outFile,"w")) == NULL) { printf ("Error %d opening '%s'n",errno,outFile); return 1; } while (fgets (buff,sizeof (buff),fIn) != NULL) { fputs (buff,fOut); } fclose (fOut); fclose (fIn); return 0; }

这给出了将所有条目写入单个文件的基准数字,并且在一秒之内运行。

现在让我们有一个每两百行打开一个文件文件 – 这就是如果文件已经被客户排序,你会看到的行为:

#include <stdio.h> #include <string.h> #include <errno.h> #define FOUT_STR "1234_out.dat" int main (void) { FILE *fIn,*fOut; char outFile[sizeof (FOUT_STR)]; char buff[1000]; char custNum[5]; int i = -1; if ((fIn = fopen ("data.dat",errno); return 1; } fOut = NULL; while (fgets (buff,fIn) != NULL) { i++; if ((i % 200) == 0) { if (fOut != NULL) fclose (fOut); sprintf (custNum,"%04d",i / 200); memcpy (outFile,sizeof (FOUT_STR)); memcpy (outFile,custNum,4); if ((fOut = fopen (outFile,outFile); break; } } fputs (buff,fOut); } if (fOut != NULL) fclose (fOut); fclose (fIn); return 0; }

这对于100M文件大约需要2s(0:00:02),而用200M和400M文件进行测试表明它可以线性扩展。 这意味着,一个排序的70G文件,你看在大约1400年或0:23:20。 请注意,这将是您的排序费用的顶部,你有1.5小时(1:30:00),给你一个总成本1:53:20。

现在让我们来实现一个简单的程序,它只是打开每个文件以追加每一行:

#include <stdio.h> #include <string.h> #include <errno.h> #define FOUT_STR "1234_out.dat" int main (void) { FILE *fIn,errno); return 1; } while (fgets (buff,fIn) != NULL) { memcpy (outFile,&(buff[4]),"a")) == NULL) { printf ("Error %d opening '%s'n",outFile); break; } fputs (buff,fOut); fclose (fOut); } fclose (fIn); return 0; }

当我们用100M文件运行这个时,需要244s(0:04:04)。 再次,用200M和400M文件进行测试表明线性缩放。 所以,对于70G文件来说,这将是47:26:40,而不是对你的分两小时分类和处理选项的改进。

但是,让我们尝试一个不同的方法,使用下面的程序,每次通过输入文件保存一百个文件句柄(完成一百次):

#include <stdio.h> #include <string.h> #include <errno.h> #define FOUT_STR "1234_out.dat" int main (void) { FILE *fIn,*fOut[100]; char outFile[sizeof (FOUT_STR)]; char buff[1000]; int seg,cust; char segNum[3],custNum[3]; for (seg = 0; seg < 100; seg++) { sprintf (segNum,"%02d",seg); if ((fIn = fopen ("data.dat",errno); return 1; } for (cust = 0; cust < 100; cust++) { sprintf (custNum,cust); memcpy (outFile,sizeof (FOUT_STR)); memcpy (outFile+0,segNum,2); memcpy (outFile+2,2); if ((fOut[cust] = fopen (outFile,outFile); return 1; } } while (fgets (buff,fIn) != NULL) { if (memcmp (&(buff[4]),2) == 0) { cust = (buff[6] - '0') * 10 + buff[7] - '0'; fputs (buff,fOut[cust]); } } for (cust = 0; cust < 100; cust++) { fclose (fOut[cust]); } fclose (fIn); } return 0; }

这是一个实际处理输入文件一百次的轻微变化,每次只处理一百个单独输出文件的行。

当它在100M文件上运行时,大约需要28s(0:00:28)。 对于200M和400M的文件来说,这似乎是线性的,所以70G文件应该是5:26:40。

甚至还没有接近亚2小时的数字。

那么当我们一次打开一千个输出文件时会发生什么:

#include <stdio.h> #include <string.h> #include <errno.h> #define FOUT_STR "1234_out.dat" int main (void) { FILE *fIn,*fOut[1000]; char outFile[sizeof (FOUT_STR)]; char buff[1000]; int seg,cust; char segNum[2],custNum[4]; for (seg = 0; seg < 10; seg++) { sprintf (segNum,"%01d",errno); return 1; } for (cust = 0; cust < 1000; cust++) { sprintf (custNum,"%03d",1); memcpy (outFile+1,3); if ((fOut[cust] = fopen (outFile,1) == 0) { cust = (buff[5] - '0') * 100 + (buff[6] - '0') * 10 + buff[7] - '0'; fputs (buff,fOut[cust]); } } for (cust = 0; cust < 1000; cust++) { fclose (fOut[cust]); } fclose (fIn); } return 0; }

这个100M文件大约需要12秒钟,并且会在2:20:00给我们,接近这个数字,但是还不够。

不幸的是,当我们进行下一个合乎逻辑的步骤时,试图一次打开整个10000个文件,我们看到:

Error 24 opening '1020_out.dat'

这意味着我们终于达到了极限(标准输入,标准输出,标准错误和大约1019个其他文件句柄),这表明1024句柄是关于我们允许的全部。

所以也许排序和处理方法是最好的方法

我不知道在Unix平台上的限制,但是在Windows中,您可以使用WINAPI打开任意数量文件,或者使用_setMaxstdio来设置打开文件句柄的最大数量认情况下为512(使用fopen)。

这里有一个类似的解决方案,可以帮助你!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐