在基于Cortex M4的平台上运行的C ++应用程序中,我已将FatFS有效地集成了。
我的应用程序包括将数据记录为称为MDF的数据格式。
在实现方面,我将数据分批记录到一个给定的文件中;缓冲区的数量取决于我获取数据的速度:一个缓冲区的日志批处理。 。 。做其他的事情。 。 。日志批处理五个缓冲区。 。 。做其他的事情。 。 。等
还有一个24字节的标头,其中包含数据的字节数。在PC上,我只需要在测量结束时保存接头,但这是一种嵌入式产品,可以在任何时间点断电。如果我不定期保存标题,则文件会“损坏”。
因此,为了保持一致性,我需要在保存每一批数据后重新保存标头,这就是我的问题所在。
这意味着我必须先写入f_lseek
,然后再写入标题,然后再写入一批数据。
我 am 使用f_cache_fptr
,因此f_lseek
的速度虽然不会很慢,但我希望避免如此频繁地致电f_lseek
。
问题
是否有可能以某种方式具有2个查找位置,这样我就不需要调用f_seek
在标头位置和数据位置之间进行乒乓了吗?
我愿意修改FatFS。
从底层看,问题比较简单,因为标头仅与数据共享一个 512字节扇区:标头为24字节,后为488字节。
答案 0 :(得分:3)
是否可以以某种方式有2个查找位置,这样我就不需要在标题位置和数据位置之间调用f_seek进行乒乓球了?
据我所知,不,这似乎没有任何意义。 FIL
仅具有一个当前位置,指示下一个写入该数据的位置。出现两个甚至意味着什么?系统如何知道要写在哪里?同时写两个地方的
尤其要注意,对于某些操作系统和文件系统,可以多次打开同一文件,但是可以FatFS supports duplicate file opens only when all openings involved are for read-only mode。
我想可以修改FatFS,使其能够在您查找另一个文件时存储一个文件的位置,然后再返回到第一个文件。因此,这意味着向FIL
结构中添加至少一个成员,并添加至少一个新函数。
但是,为什么要对FatFS的内脏m之以鼻?至少会有一点风险。只要您仍然要添加一个函数,在现有函数之上仅实现一个FRESULT my_f_write_at_beginning(FIL* fp, const void* buff, UINT btw, UINT* bw)
怎么样?它可以存储当前位置,搜索到文件的开头,执行写操作(也许确保已写入指定的完整字节数),然后搜索回到原始位置。
但是从根本上讲,没有,没有来回回跳的方式,因为这样做是您提出的要求的一部分。
答案 1 :(得分:0)
在PC上,我只需要在测量结束时保存接头,但这是一个嵌入式产品,可以在任何时间点断电。如果我不定期保存标题,则文件会“损坏”。
因此,为了保持一致性,我需要在保存每一批数据后重新保存标头,这就是我的问题所在。
更正确;您需要保存缓冲区和标头(页脚?),并更新目录条目以反映新的文件大小,并更新文件分配表以解决分配的扇区;而且您需要“原子地”至少写入3个完全独立的扇区,以便在错误的时间出现电源故障时一切保持一致。
在大多数硬件上这并非完全可能。
但是,有一种方法可以“比较安全”地进行。具体来说:
为文件的全新副本(包括要附加到末尾的新数据)预分配足够的群集,并相应地更新文件分配表。如果在执行此操作时(或在此之后立即)发生电源故障,则可能会丢失群集,这是一个“无法忽略的”问题,将浪费一些空间,但可以使用典型的“检查磁盘”实用程序轻松修复。 / p>
在预分配的群集中创建文件数据的全新副本(复制旧数据,然后附加新数据和标头)。如果在执行此操作时(或在此之后紧接)发生电源故障,则风险与之前相同-仅丢失了一些群集(可忽略)。
以原子方式更新目录条目;使用相同的原子(单个扇区)写入更改文件大小和“起始群集号”。如果在此之后发生电源故障,则风险是相同的群集丢失(文件数据的旧版本位于此位置,而不是文件数据的新版本位于该位置)。
释放执行操作所使用的文件的旧版本写入文件分配表的群集。在此之后,您已经成功完成操作,因此可以断电。
为减少性能,您可以有两个“集群链”并在它们之间交替进行;这样,一个集群链将用于文件的当前版本,另一个集群将成为文件的下一个版本。这样就避免了将许多较旧的数据从一个位置复制到另一位置的需要(如果您知道旧数据仍在以前使用的群集中)。它还可以避免在文件分配表中分配和释放大多数群集的需要,但是这样做只会大大增加丢失群集的风险。
当然,要使这一切正常进行,您需要保证单扇区写入是原子的。并且您不能使用FAT12(文件分配表中的条目可以按扇区边界分割)。