如何通过行块处理C中的文本文件?

我正在用C编写一个处理文本文件的程序,并跟踪每个唯一的单词(通过使用一个结构,该结构具有该单词的char数组和其出现次数的计数)并将该结构存储到数据结构中。 但是,分配包括:“整个txt文件可能非常大,无法保存在主内存中。请在程序中考虑这一点。”

我下课后问他,并说他一次读X行文本文件(我认为20,000是他的建议?),一次分析它们并更新结构,直到你到达文件末尾。

任何人都可以帮助解释这样做的最佳方式并告诉我使用哪些function? 我对C.非常非常新。

(我目前的程序对于小文件是准确和正确的,我只需要让它容纳大量文件)。

非常感谢!!

编辑:

fp = fopen(argv[w], "r"); if ((fp) == NULL){ fprintf( stderr, "Input file %s cannot be opened.\n", argv[w] ); return 2; } /* other parts of my program here */ char s[MaxWordSize]; while (fscanf(fp,"%s",s) != EOF){ nonAlphabeticDelete(s); // removes non letter characters toLowerCase(s); //converts the string to lowercase //attempts to add to data structure pthread_mutex_lock(&lock); add(words, &q, s); pthread_mutex_unlock(&lock); } 

这是有效的,我只需要调整它一次通过文本文件去X行。

getline()怎么样? 这里是手册http://man7.org/linux/man-pages/man3/getline.3.html的一个例子

  #define _GNU_SOURCE #include  #include  int main(void) { FILE *stream; char *line = NULL; size_t len = 0; ssize_t read; stream = fopen("/etc/motd", "r"); if (stream == NULL) exit(EXIT_FAILURE); while ((read = getline(&line, &len, stream)) != -1) { printf("Retrieved line of length %zu :\n", read); printf("%s", line); } free(line); fclose(stream); exit(EXIT_SUCCESS); } 

最好通过阅读一些手册来完成,但我可以提供一个开头。

 FILE *fp; fp=fopen("fileToRead.txt", "rb"); if (!fp) { /* handle failure! */ } #define GUESS_FOR_LINE_LENGTH 80 char sentinel = '\0'; while ((sentinel = getc(fp)) != EOF) { ungetc(sentinel, fp); char buffer[20000*GUESS_FOR_LINE_LENGTH]; size_t numRead = fread(buffer, 1, 20000*GUESS_FOR_LINE_LENGTH, fp); if (numRead < 20000*GUESS_FOR_LINE_LENGTH) { /*last run */ } /* now buffer has numRead characters */ size_t lastLine = numRead - 1; while (buffer[lastLine] != '\n') { --lastLine; } /* process up to lastLine */ /* copy the remainder from lastLine to the front */ /* and fill the remainder from the file */ } 

这更像是伪代码。 由于您大多数都有工作程序,因此您应该将其作为指南。

首先尝试一次读一行。 扫描行缓冲区中的字边界并微调字计数部分。 使用哈希表来存储单词和计数似乎是一种很好的方法。 使输出可选,以便您可以测量读/解析/查找性能。

然后制作另一个程序,对核心部分使用相同的算法,但使用mmap读取文件的大部分并扫描内存块。 棘手的部分是处理块边界。

比较两个程序在一组巨大文件上的输出,确保计数相同。 您可以通过多次连接同一文件来创建大文件。

比较时间也是如此。 使用time命令行实用程序。 禁用此基准测试的输出以专注于读/解析/分析部分。

将时间与其他程序(如wccat - > /dev/null 。 一旦获得类似的性能,瓶颈就是从大容量存储中读取的速度,没有太多的空间可以改进。

编辑:看看你的代码,我有这些评论:

  • fscanf可能不是正确的工具:至少你应该保护缓冲区溢出。 你应该如何处理foo,bar 1个单词还是2个单词?

  • 我建议使用fgets()fread并沿缓冲区移动指针,跳过非字字节,将字节字节转换为小写,间接通过256字节数组,避免复制。

  • 通过预处理器变量使锁定内容可选。 如果words线程仅访问words结构,则不需要它。

  • 你是如何实现add ? 什么是q