如何通过行块处理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
命令行实用程序。 禁用此基准测试的输出以专注于读/解析/分析部分。
将时间与其他程序(如wc
或cat - > /dev/null
。 一旦获得类似的性能,瓶颈就是从大容量存储中读取的速度,没有太多的空间可以改进。
编辑:看看你的代码,我有这些评论:
-
fscanf
可能不是正确的工具:至少你应该保护缓冲区溢出。 你应该如何处理foo,bar
1个单词还是2个单词? -
我建议使用
fgets()
或fread
并沿缓冲区移动指针,跳过非字字节,将字节字节转换为小写,间接通过256字节数组,避免复制。 -
通过预处理器变量使锁定内容可选。 如果
words
线程仅访问words
结构,则不需要它。 -
你是如何实现
add
? 什么是q
?