什么更有效,从文件中逐字读取或一次读取一行并使用C分割字符串?

时间:2013-01-22 04:05:50

标签: c file processing-efficiency

我想在C中开发一个应用程序,我需要从磁盘上的文件逐字检查。我被告知,从文件中读取一行然后将其拆分为单词会更有效,因为需要更少的文件访问。这是真的吗?

6 个答案:

答案 0 :(得分:8)

如果您知道自己将需要整个文件,那么您也可以尽可能以大块的形式阅读它(在极端情况下,您将内存将整个文件一次性映射到内存中) 。你说得对,这是因为需要更少的文件访问。

但是如果你的程序速度不慢,那么就把它写成最快且最无bug的开发方式。早期优化是一个严重的罪。

答案 1 :(得分:5)

不正确,假设您将使用scanf(),并且您对'word'的定义与scanf()将其视为单词的内容相匹配。

标准I / O库将缓冲实际磁盘读取,读取行或字将在磁盘访问方面具有基本相同的I / O开销。如果您使用fread()阅读文件的大块,您可能会获得一些好处 - 但代价是复杂。

但是对于阅读单词,如果您的数组为scanf(),则%99s和保护性字符串格式说明符(例如char word[100];)可能会正常工作并且编码可能更简单。

如果您对单词的定义比scanf()支持的定义更复杂,那么阅读行和拆分可能更容易。

答案 2 :(得分:2)

就分裂而言,性能方面没有区别。您正在使用一个案例中的空格和另一个案例中的换行符进行拆分。

然而,对于单词的情况,你将需要分配缓冲区M次,而在行的情况下它将是N次,其中M> N.因此,如果您采用单词拆分方法,请首先尝试计算总内存需求,分配那么多块(因此您不会最终得到碎片化的M块),然后从该块中获取M个缓冲区。请注意,相同的方法可以应用于分割线,但差异将不太明显。

答案 3 :(得分:1)

这是正确的,您应该将它们读入缓冲区,然后将其拆分为您定义为“单词”的内容。 唯一不合适的情况是,如果你能让fscanf()正确地抓住你认为是单词的内容(可疑)。

答案 4 :(得分:0)

主要的性能瓶颈可能是:

  • 对stdio文件I / O功能的任何调用。呼叫越少,开销越少。
  • 动态内存分配。应该尽可能地完成。最终,对malloc的大量调用将导致堆分割。

因此,它归结为一个经典的编程考虑因素:您可以获得快速执行时间,也可以获得较低的内存使用率。你不能同时获得这两者,但你可以找到一些在执行时间和内存消耗方面最有效的合适中间地带。

在一个极端情况下,可以通过将整个文件作为一个大块读取并将其上传到动态内存来获得最快的执行速度。或者到另一个极端,您可以逐字节读取它并在读取时对其进行评估,这可能会使程序变慢但根本不会使用动态内存。

您需要具备各种CPU特定和操作系统特定功能的基础知识,才能最有效地优化代码。对齐,缓存内存布局,底层API函数调用的有效性等问题都很重要。

为什么不尝试一些不同的方法并对它们进行基准测试?

答案 5 :(得分:0)

实际上并没有回答你的确切问题(单词与行),但如果你无论如何都需要同时记忆中的所有单词,那么最有效的方法是:

  1. 确定文件大小
  2. 为整个文件分配缓冲区加上一个字节
  3. 将整个文件读入缓冲区,并将'\0'放入额外字节。
  4. 传递它并计算它有多少单词
  5. 分配char*(指向单词的指针)或int(索引到缓冲区)索引数组,大小匹配字数
  6. 对缓冲区进行第二次传递,并将地址或索引存储到索引数组的第一个字母,并使用'\0'(字符串结束标记)覆盖缓冲区中的其他字节。
  7. 如果你有足够的内存,那么假设单词数最差的情况可能会稍快一些:(filesize+1) / 2(一个字母的单词之间有一个空格,文件中有奇数个字节)。同时将Java ArrayList或Qt QVector方法与索引数组一起使用,并在字数超过当前容量时使用realloc()将其大小加倍,这将非常有效(由于倍增=指数增长,重新分配不会多次发生)。