【问题标题】:Is it possible to count the frequency of a word in a file precisely using two buffers in C?是否可以使用 C 中的两个缓冲区精确计算文件中单词的频率?
【发布时间】:2020-07-14 12:35:20
【问题描述】:

我有一个大小为 1GB 的文件。我想知道在文件中找到了多少次“sosowhat”这个词。我已经使用 fgetc() 编写了一个代码,它一次从文件中读取一个字符,对于 1GB 大小的文件来说这太慢了。所以我创建了一个大小为 1000 的缓冲区(使用 mmalloc)来一次保存文件中的 1000 个单词,我使用 strstr() 函数来计算单词“sosowhat”的出现次数。逻辑很好。但问题是,如果“sosowhat”的“so”部分位于缓冲区的末尾,而“sowhat”部分位于新缓冲区中,则不会计算该单词。所以我使用了两个缓冲区 old_buffer 和 current_buffer。在每个缓冲区的开头,我想检查旧缓冲区的最后几个字符。这可能吗?我怎样才能回到旧缓冲区?没有 memmove() 可以吗?作为初学者,我会非常乐意为您提供帮助。

【问题讨论】:

标签: c file-io buffer


【解决方案1】:

是的,可以做到。有更多可能的方法。

第一个是最干净的,按照建议保留第二个缓冲区,该缓冲区的长度与搜索词的长度相同,您保留旧缓冲区的最后一块。 (因为您存储了wordLength - 1 个字符+NULL 终止符,所以它必须是搜索词的长度)。然后最快的方法是将旧缓冲区中的第一个 wordLen - 1 字符附加到这个存储的块中,然后在此处搜索您的单词。然后继续正常搜索。 - 当然,您可以创建一个可以容纳两个块的缓冲区(旧缓冲区的最后一个字节和新缓冲区的第一个字节)。

另一种方法(我不推荐,但在代码方面可能会更容易一些)是在读取文件中向后移动 fseek wordLen - 1 字节。这会将先前方法中存储的块“移动”到下一个缓冲区。这有点脏,因为您将读取文件的某些内容两次。虽然这在性能方面并不明显,但我再次建议不要这样做,并使用类似于第一种描述的方法。

【讨论】:

  • 据我了解,如果使用 malloc 制作大小为 1000 的缓冲区,则文件中的字符将是 999 个字符,第 1000 个位置将为 NULL?
  • @SharonShelton:如果您在该缓冲区中存储一个以 null 结尾的字符串,那么可以。字符串长度将限制为 999 个字符和后续的空终止符。如果你使用函数fgets,那么它总是会写一个空终止符。但是,如果您使用用于二进制数据的函数,例如fread,则它不会写入空终止符,您可以使用全部 1000 个字节。但是,在这种情况下,我建议您使用以 null 结尾的字符串,因此不要使用 fread
  • @SharonShelton:如果你使用fgetc而不是fgets,则不会自动写入空终止符,你必须自己编写或使用其他方法来跟踪长度的数据。
  • @SharonShelton:使用 fread 读取 1000 个字节与调用 fgetc 恰好 1000 次相同。它不会写入空终止符。因此,如果您使用这些函数,则必须自己跟踪缓冲区中有效数据的长度,或者您可以编写自己的空终止符。
【解决方案2】:

使用与fgetc 相同的算法,仅从您创建的缓冲区中读取。它与 strstr 逐个字符地遍历字符串的效率相同。

【讨论】:

  • 但是当搜索到的单词位于2个单独的文件读取中时,您如何处理?
  • 你可以避免这个问题逐字符读取。当您到达缓冲区的末尾时,您开始从另一个缓冲区读取。
  • @P__J__ 无法使用 fgetc() 从缓冲区中获取字符。 fgetc() 只能直接从文件中读取字符
  • @SharonShelton 编写函数 getCharFromBuffer。顺便说一句,也可以使用 fgetc,但您需要向文件系统添加对缓冲区的支持(如何取决于操作系统硬件和实现)
  • strstr 可能使用像 Boyer-Moore 这样的算法,不需要查看每个字符
猜你喜欢
  • 2017-06-06
  • 1970-01-01
  • 1970-01-01
  • 2015-06-14
  • 1970-01-01
  • 2011-05-30
  • 1970-01-01
  • 2011-07-21
  • 1970-01-01
相关资源
最近更新 更多