0

我在基于 Cortex M4 的平台上运行的 C++ 应用程序中集成了 FatFS。

我的应用程序包括将数据记录到称为MDF的数据格式。

在实现方面,我将数据(到给定文件)成批地记录在缓冲区中;缓冲区的数量取决于我获取数据的速度: log batch of one buffer 。. . 做其他事情。. . 日志批处理五个缓冲区。. . 做其他事情。. . 等等

还有一个 24 字节的标头,包含数据的字节数。在 PC 上,我只会在测量结束时保存标头,但这是一种嵌入式产品,可以随时断电。如果我不定期保存标题,文件就会“损坏”。

因此,为了保持一致性,我需要在保存每批数据后重新保存标题,这就是我的问题所在。

这意味着我必须f_lseek在写标题之前调用,然后再写这批数据。

正在使用f_cache_fptr所以f_lseek速度并不慢,但我想避免需要f_lseek如此频繁地打电话。

问题

是否有可能以某种方式拥有 2 个搜索位置,这样我就不需要f_seek在标题位置和数据位置之间调用乒乓球?

我愿意修改 FatFS。

在底层,问题更简单,因为标头只与数据共享一个512 字节的扇区:24 字节的标头,然后是 488 字节的数据。

4

2 回答 2

3

是否有可能以某种方式拥有 2 个查找位置,这样我就不需要调用 f_seek 来在标题位置和数据位置之间进行乒乓操作?

据我所知,没有,而且这似乎没有任何意义。AFIL只有一个当前位置,指示写入它的下一个数据将去往何处。有两个甚至意味着什么?系统如何知道在哪里写入?写信到这两个地方肯定是不正确的。

特别要注意的是,对于某些操作系统和文件系统,可以多次打开同一个文件,但是FatFS 仅在所有涉及的打开都是只读模式时才支持重复文件打开

我想可以修改 FatFS 使其能够在您寻找另一个文件位置时存储一个文件位置,然后再返回第一个位置。所以这意味着向FIL结构中添加至少一个成员,并添加至少一个新功能。

但是为什么要搞乱 FatFS 的内部呢?这至少会有一点风险。只要您无论如何都必须添加一个功能,那么FRESULT my_f_write_at_beginning(FIL* fp, const void* buff, UINT btw, UINT* bw) 在现有功能之上实现一个怎么样?它可以存储当前位置,寻找到文件的开头,执行写入(可能确保写入指定的全部字节数),然后寻找回到原始位置。

但从根本上说,不,没有来回逃避乒乓球,因为这样做是您提出的要求的一部分。

于 2019-05-23T20:31:02.203 回答
0

在 PC 上,我只会在测量结束时保存标头,但这是一种嵌入式产品,可以随时断电。如果我不定期保存标题,文件就会“损坏”。

因此,为了保持一致性,我需要在保存每批数据后重新保存标题,这就是我的问题所在。

更正确;您需要保存缓冲区和页眉(页脚?),并更新目录条目以反映新的文件大小,并更新文件分配表以说明分配的扇区;并且您需要“原子地”写入至少 3 个完全独立的扇区,以便在错误的时间出现电源故障时一切都保持一致。

这在大多数硬件上并不完全可能。

但是,有一种方法可以“稍微安全”地做到这一点。具体来说:

  • 为文件的全新副本(包括要附加到末尾的新数据)预先分配足够的簇,并相应地更新文件分配表。如果在执行此操作时(或在此之后立即)发生电源故障,则风险是丢失集群,这是一个“可忽略”的问题,会浪费一些空间,但可以使用典型的“检查磁盘”实用程序轻松修复。

  • 在预先分配的集群中创建文件数据的全新副本(复制旧数据,然后附加新数据和标题)。如果在执行此操作的过程中(或在此之后立即)发生电源故障,则风险与以前相同 - 只是一些丢失的集群(可忽略)。

  • 自动更新目录条目;使用相同的原子(单扇区)写入更改文件大小和“起始簇号”。如果在此之后发生电源故障,则风险是相同的丢失集群(文件数据的旧版本所在的位置,而不是文件数据的新版本所在的位置)。

  • 释放旧版本文件通过写入文件分配表使用的簇。在这之后你已经成功完成了,所以电源故障是可以的。

为了让性能不那么糟糕,你可以有两个“集群链”并在它们之间交替;这样一个集群链用于文件的当前版本,另一个将成为文件的下一个版本。这避免了将大量旧数据从一个地方复制到另一个地方的需要(如果您知道旧数据仍在以前使用的集群中)。它还可以避免在文件分配表中分配和释放大多数簇的需要,但只会显着增加丢失簇的风险。

当然,要使所有这些工作,您需要保证单扇区写入是原子的;并且您不能使用 FAT12(文件分配表中的条目可以按扇区边界分割)。

于 2019-05-23T23:03:44.383 回答