从C中的文本文件中读取

时间:2011-11-25 01:16:52

标签: c scanf

真的是一个小问题。阅读包含X个单词的文本文件,并将每个单词逐个添加到链表中最佳。即青蛙是老的。

因此,The,Frog,Is和Old都会被放入ListNode,所有这些都是从文件中读取的。

我真的想知道与fscanf一起使用的最佳功能,如果fscanf是最好的选择。所有建议都很棒!

干杯。

编辑: 我的查询真的是,如果我想解析一个大文本文件,最好将每个单词逐个fscanf成一个数组,添加到列表,自由数组,并重复?或者是否有更有效的方式

3 个答案:

答案 0 :(得分:3)

“%s”转换说明符将匹配非空格字符。

#define QUOTE(s) #s
#define STR(s) QUOTE(s)

#ifndef BUFSIZE
#  define BUFSIZE 255
#endif

char buf[BUFSIZE+1];
while (fscanf(fin, "%" STR(BUFSIZE) "s", buf)) {
    /* buf holds next word. Todo:
       + allocate space for word
       + copy word to newly allocated space
       + add to linked list
     */
}

或者,strtok可用于使用您指定的一组字符(作为字符数组)将字符串标记(拆分)为子字符串。您的系统可能还有strsep,用于替换strtokstrtokstrsep都会修改您传入的数组,因此请注意,这不会导致访问数据的其他代码部分出现问题。 strsep不是线程安全的;如果您有多个线程访问要解析的字符串,请使用strsepstrtok_r

#ifndef BUFSIZE
#  define BUFSIZE 256
#endif

const char separators[] = "\t\n\v\r\f !\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~";
char buf[BUFSIZE], *line, *word, *rest;

while (fgets(buf, BUFSIZE+1, fin)) {
    rest = line = buf;
    while ((word = strtok_r(line, separators, &rest))) {
        /* Todo:
           + allocate space for word
           + copy word to newly allocated space
           + add to linked list
        */
        line=rest;
    }
}

由于第二个示例从strtok_r的文件中一次读取一行,如果该文件的任何行超过BUFSIZE-1个字符且BUFSIZE-1 st 和BUFSIZE th 一行中的字符都是字母,第二个例子将两个字分开。解决这个问题的方法是创建一个缓冲的字符串流,这样当缓冲区的末尾到达时,缓冲区中剩余的任何内容都会转移到前面,缓冲区的其余部分会被文件中的更多数据填充(只是请注意比缓冲区更长的单词;在生产代码中,这是一个潜在的安全漏洞,可能导致拒绝服务攻击。)

所有上述功能的一个问题是它们不处理输入中的空字符。如果您希望解析可能包含空字符的数据,则需要使用非标准函数,其中包括编写自己的函数。

至于效率,你使用的任何算法都需要从文件中读取(复杂度为O(n),并且需要I / O,减慢程序速度)并分配内存来存储单词。无论您使用fscanfstrtok还是其他方法,时间和空间复杂度都不会有太大变化;关于唯一可能的事情是分配了多少个中间缓冲区。找到最有效的实现方法的最佳选择是尝试一对并对其进行分析。

答案 1 :(得分:1)

你不应该寻找“一种更有效的方式”,直到你的“方式不够有效”。

strtok之类的内容可能会满足您的需求而不需要malloc。它可以让您在适当的位置划分字符串 。 (小心使用!)

答案 2 :(得分:1)

如果你在现代台式电脑上寻找高速......你可以去多线程。

  • 一个线程填充一个字符缓冲区,比如4Ko,只做这个
  • 一个线程读取缓冲区,解析单词并将它们添加到列表中
  • 如果您不需要整个列表
  • ,一个线程会执行您在列表中的任何操作

这个想法是在等待I / O时进程不会休眠。如果您拥有大量CPU核心,那么要获得更高的速度,就是将文件切成大块,一个核心处理一个块。很复杂的代码和错误的机会,但嘿,速度是不便宜...