【问题标题】:How often shoud a file be opened and closed when constantly writing data to a file (SDCard)?在不断将数据写入文件(SDCard)时,应该多久打开和关闭文件?
【发布时间】:2019-09-13 11:14:49
【问题描述】:

我正在开发一个带有 ESP32 的 CAN-BUS 记录器。使用 fprintf 将数据写入 SDCard。

我知道我必须使用 fopen() 来打开文件,然后再使用 fclose() 来关闭文件。

我的问题是我应该多久打开和关闭一次文件?只打开一次,然后可能一个小时后关闭它?还是打开,写100个值,关闭,再打开?

我不想丢失大量数据。当带有 CAN-BUS 的摩托车运行时,ESP32 将亮起。如果点火开关关闭,ESP32 将不再通电。我不介意最后 5 秒的数据是否丢失。但我不希望丢失 10 分钟的数据。

我还看到了 fflush() 函数。我应该定期使用它,即每 10 秒一次吗?然后如果文件从不关闭也许没问题?

更多信息:我可以设计设备以确保电源开启足够长的时间,以便执行 fclose()(在此之前没有电源故障)。但如果我不介意最后几秒钟的数据丢失,我想这并不是真的必要。

我把这个问题放到 StackOverflow 中而不是电气工程中,因为这是关于为那个项目编写代码。

我在这里搜索并找到了类似的问题,但我并没有真正找到这个问题的答案。

【问题讨论】:

  • 您可以随意打开和关闭文件多少次。您只需要考虑打开/关闭文件的执行开销。最好的解决办法可以是缓冲数据的时间可以松动,5秒,并且每5秒更新一次文件。在大型系统上可能还有其他技术,但你应该是一个嵌入式应用程序,我想文件系统代码在功能上是有限的。
  • ESP32 芯片是否支持掉电中断?如果您有支持硬件来保证一定时间的供电,那么在掉电中断中调用fclose() 可能是一个有效的选择。

标签: c file sd-card


【解决方案1】:

fflush 的 Linux 手册页包含一个非常重要的警告:

注意事项 请注意, fflush() 仅刷新 C 库提供的用户空间缓冲区。为确保数据物理存储在磁盘上,内核缓冲区也必须刷新,例如使用sync(2)fsync(2)

syncfsync 是 Posix 接口的一部分,它们可能类似于也可能不类似于 ESP32 上的底层文件 i/o 接口。但警告可能仍然值得留意。

C 标准对fflush 有这样的措辞,这清楚地表明,所有保证是fflush 刷新由 C 库维护的缓冲区,类似于 Linux 手册页中的措辞:

fflush 函数会导致该流的任何未写入数据被传递到主机环境以写入文件…

因此,如果您希望将数据实际提交到磁盘,fflush 通常是不够的。

【讨论】:

    【解决方案2】:

    我做了一些测试来回答我的问题。

    首先我使用了这段代码:

    ESP_LOGI(TAG, "Opening file");
    FILE* f = fopen(fileName1, "a");
    if (f == NULL) {
        ESP_LOGE(TAG, "Failed to open file for append");
        return;
    }
    int64_t t = 0;
    for (unsigned long i = 1; i <= 10009000; i++)
    {
        t = esp_timer_get_time();
        fprintf(f, "%010" PRId64, t);
        fprintf(f, " ");
        fprintf(f, "%10lu\n", i);
    
        if (0 == i % 10000){
            ESP_LOGI(TAG, "Flush file");
            fflush(f);
        }
    }
    //fclose(f);
    ESP_LOGI(TAG, "File written");
    

    请注意该文件永远不会关闭。

    当我在我的 ESP32 上运行该代码时,文件已创建,但没有任何内容写入文件。所以至少我的配置 fclose() 是必要的。

    当我把代码改成这样时:

    for (unsigned long i = 1; i <= 109000; i++)
    {
        t = esp_timer_get_time();
        fprintf(f, "%010" PRId64, t);
        fprintf(f, " ");
        fprintf(f, "%10lu\n", i);
    
        if (0 == i % 10000){
            //fflush(f);
            ESP_LOGI(TAG, "Close and Open file");
            fclose(f);
            f = fopen(fileName1, "a");
        }
    }
    //fclose(f);
    ESP_LOGI(TAG, "File written");
    

    然后将数据写入文件。在这种情况下,文件中的最后一行是

    0013521402 100000

    因此,正如预期的那样,100,000 之后(最后一次关闭文件)和 109,000 之前(i

    我的结论是:我必须使用 fclose()。如果我只是定期使用 fflush(),程序不会写任何东西。我必须多久关闭和打开文件取决于我准备丢失多少数据。对于我的应用程序,我将在经过一些测试后做出决定。也许我会关闭并打开文件,即每 5 秒。或者我会在写完 1000 行或类似的东西后这样做。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-28
      • 2020-06-02
      • 1970-01-01
      • 2016-09-10
      • 2011-06-19
      • 1970-01-01
      • 2013-12-20
      • 1970-01-01
      相关资源
      最近更新 更多