【问题标题】:write/read file performance issue in CC中的写入/读取文件性能问题
【发布时间】:2012-11-30 22:41:14
【问题描述】:

我在用 C 读写文件时遇到性能问题。这是我的问题和解决方案,但速度很慢:

我有一个 ASCII 文件,我认为其中的每一行都是一条记录。我必须根据文件中某个位置存在的特定数字将此文件分成两个。 例如,如果位置 10 的数字为 0,则记录进入 file1,如果为 1,则记录进入 file2。

我所做的是打开输入文件和其他两个用于输出文件的文件流。我从输入文件中读取一行,进行比较,然后该行转到 file1 或 file2,然后读取下一条记录。 它工作正常,但速度很慢。请建议一种更快的方法。

这是文件的读取方式:

bytes_read = readline(infile, (void*)buffer, line_size+1);

fwrite 用于写入文件。文件大小约为 50 MB。读取整个输入文件后关闭文件。

【问题讨论】:

  • 您应该向我们展示相关代码。对文件 I/O 进行编码有快速和慢速两种方式。也许你在做一些傻事。
  • 感谢帕迪的评论。我添加了更多有问题的信息/代码。请帮忙。
  • 你为什么要找?那会让你付出很多。如果您想丢弃接下来的 384 个字节,只需执行 fread 代替 - 默认情况下,stdio 文件流被缓冲。如果你真想找,至少用SEEK_CUR
  • 感谢 Paddy,让我探索 SEEK_CUR。
  • 举一个你的“线条”的例子

标签: c performance file-io


【解决方案1】:

您几乎已经找到了最快的方法!

  • 您有什么类型的 IO?缓冲/非缓冲?
  • 文件有多大?
  • 您是打开/关闭每一行的输出文件,还是保持打开状态?
  • 在输出文件中有任何搜索吗?
  • 阅读,哪一部分慢?写?两者都有?

IO 是程序中较慢的部分之一。一些代码可以帮助我们发现任何明显的问题。

【讨论】:

  • 感谢约翰的回复。我在问题中添加了信息。
【解决方案2】:

您可以尝试以块的形式读取文件,而不是一次读取一行。块读取可以比逐行读取快得多。如果你能把整件事读入记忆,那就太好了。如果没有,请读取一个大块,处理它并继续。

【讨论】:

    【解决方案3】:

    您可以尝试减少读/写调用的次数。

    1. 尝试一次读取 2k 字节而不是 getline()。如果您的文件不大,甚至可以读取整个文件一次。
    2. 使用缓冲写入。并且不要在每次写入后关闭文件。仅在完成整个文件的写入后关闭文件。

    【讨论】:

    • 感谢李老师的回复。如果我有 50 MB 到 70 MB 的文件,可以将整个文件加载到内存中吗?
    • 今天的计算机有很多内存,打开几页的“傻”网络浏览器可以吃掉 100-200MB 的 RAM,那么为什么你的严肃而高效的程序不能使用这么多的内存呢?
    • 谢谢卡米尔。我认为最好加载到内存中。
    • 我不确定您的应用程序是如何工作的,但如果您经常需要访问许多随机文件 - 将整个文件读入 RAM 可能比您的旧方法花费更多时间。我的意思是 - 当你需要一行时加载整个文件是没有意义的,然后你需要打开另一个文件。
    • 我曾经做过类似的项目,所以我觉得70M不算太大。如果将 70M 的文件加载一次到内存中,然后在内存中逐行解析,它应该比从文件中逐行读取要快得多。
    【解决方案4】:

    我认为您应该将所有文件读入一些数组并处理变量/数组,而不是直接在 IO 上。

    当然,如果这是可能的(您的文件很少,而不是数百)。

    如果这些文件有成百上千个 - 那么您应该考虑另一种数据存储方法。数据库就是为这样的事情而设计的。

    另一种选择是带有 CSV 存储引擎的 MySQL。

    The CSV Storage Engine at mysql.com

    但最后可能会迫使您更改文件结构。

    【讨论】:

    • 感谢亲爱的回复。文件数以千计。
    • 那么你应该考虑另一种数据存储方法。数据库就是为这样的事情而设计的。
    • 数据库有自己的限制。但我必须以文件方式做:)
    • 这些文件有多大?也许在应用程序启动时将它们读入 RAM 并不是什么坏主意?
    • 文件大小超过 50 MB,最大为 150 MB
    【解决方案5】:

    在 cmets 讨论后,我认为您的问题没有简单的答案。

    对数千个大尺寸的 CSV 文件进行有效读写真的很难。

    发明了具有更好存储引擎的数据库来避免此类性能问题。

    也许你应该看看 CSV 引擎在一些开源数据库中是如何设计的。在那里您应该找到(非常复杂的)您的问题的答案:处理许多大型 csv 文件的最佳方法是什么。

    【讨论】:

      【解决方案6】:

      如果您正在读取文件,那么最好使用 fgets。这会自动为下一个 fget 移动文件指针。

      fseek 和 ftell 正在减慢代码中的速度。试试这个。它应该更快。

      #include <stdio.h>
      #include <stdlib.h>
      
      int
      main()
      {
          char line[132];
          int line_num = 0;
          FILE *fp_r, *fp_w1, *fp_w2, *fp_w;
      
          fp_r = fopen("readfile", "r");
          if (fp_r == NULL) {
              printf("Could not open testfile\n");
              exit(0);
          }
      
          fp_w1 = fopen("writefile1", "w");
          if (fp_w1 == NULL) {
              printf("Could not open writefile1\n");
              exit(0);
          }
      
          fp_w2 = fopen("writefile2", "w");
          if (fp_w1 == NULL) {
              printf("Could not open writefile2\n");
              exit(0);
          }
      
          while (fgets(line, sizeof(line), fp_r) != NULL) {
              line_num++;
      
              if (*(line+9) == '0') {
                  fp_w = fp_w1;
              }
              else if (*(line+9) == '1') {
                  fp_w = fp_w2;
              }
              else {
                  printf("Exiting - Error at line %d\n", line_num);
                  exit(1);
              }
      
              fprintf(fp_w, line);
          }
      
          fclose(fp_r);
          fclose(fp_w1);
          fclose(fp_w2);
      
          exit(0);
      }
      

      我使用的readfile是

      01234567 0 This is the line with 0 at position 10
      01234567 1 This is the line with 1 at position 10
      

      【讨论】:

      • 感谢 Arun 的回复。我只使用 readline。无论如何,让我试试 fgets。
      猜你喜欢
      • 2012-11-30
      • 1970-01-01
      • 2021-12-26
      • 1970-01-01
      • 1970-01-01
      • 2011-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多