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

时间:2015-12-04 04:56:03

标签: c file text chunks

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

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

任何人都可以帮助解释这样做的最佳方法并告诉我使用哪些功能?我对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行。

3 个答案:

答案 0 :(得分:1)

getline()怎么样? 以下是联机帮助页http://man7.org/linux/man-pages/man3/getline.3.html

中的示例
   #define _GNU_SOURCE
   #include <stdio.h>
   #include <stdlib.h>

   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);
   }

答案 1 :(得分:0)

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

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 */
}

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

答案 2 :(得分:0)

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

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

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

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

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

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

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

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

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

  • 您是如何实施add的?什么是q