c++ - 如何确保目录对象的读取索引在 FATFS 中倒带?
问题描述
我猜这是一个基本问题:我正在使用 FatFs 中的 f_readdir 函数从命令行读取目录的内容,但我无法让该函数多次运行。第一次运行很好:我在 CLI 中键入“目录”,它会实时显示目录中的每个文件。然而,要求它再次重复 f_readdir 操作(即,在第一个成功完成后再次键入“目录”命令)不会输出任何内容。
我相信这是因为文件读取对象在 f_readdir 操作结束时没有被倒回到零,并且后续读取目录的请求从不存在的索引部分开始。这是我目前能看到的最好的解释,至少。它在 Elm Chan 的FatFs 网站上说:“当所有目录项都已读取且没有要读取的项时,将一个空字符串存储到 fno->fname[] 中而没有任何错误。当给 fno 一个空指针时,目录对象的读取索引被倒带。”
这是我的代码。忽略函数参数,它们是运行命令的 RTOS 东西:
void Cmd_directory::run(XString param, XRTOS::XCLI::userIO* io){
DIR dj; /*[IN] Directory search object */
FILINFO fno; /*[OUT] File information structure */
FRESULT res;
res = f_opendir(&dj, "0:");
while (res == FR_OK && fno.fname[0]) {
res = f_readdir(&dj, &fno);
io->print((const char*)fno.fname);
io->print("\r\n");
}
f_closedir(&dj);
}
这个 while 循环是我在网上找到的,所以不幸的是,我不完全理解 fname 索引的工作原理,就像我阅读了详细解释一样多次。也许它没有意识到它正在根据我的 while 循环的条件到达目录的末尾,尽管它肯定会成功完成并关闭目录。当我再次运行该函数时,我可以看到 fno 对象中仍然存储有前一次运行的文件信息。
我尝试过的事情(在这一点上值得补充一下,我对编程世界很陌生):
&fno = nullptr; //produces "error: lvalue required as left operand of assignment"
FILINFO *p = nullptr; //produces all sorts of errors
fno = p;
//these were shots in the dark
fno.fname[0] = 0;
memset(fno.fname, 0, sizeof(fno.fname));
我想这是一些我没有得到的基本东西,但如果我在这方面做得不好,请原谅我。不幸的是,我无法访问真正的程序员IRL,所以我不得不对社区进行民意调查。
哦,对了,我正在使用 Eclipse IDE、GNU ARM 构建工具和 STM32L。
解决方案
这里:
while (res == FR_OK && fno.fname[0]) {
fno.fname[0]
是单元化的 - 你第一次很幸运,因为它包含非零垃圾。第二次它可能包含之前留在其中的任何函数 - 即来自先前调用的 NUL - 这会立即终止循环。
以下应该有效:
res = f_readdir( &dj, &fno ) ;
while( res == FR_OK && fno.fname[0] )
{
io->print((const char*)fno.fname);
io->print("\r\n");
res = f_readdir(&dj, &fno);
}
fno.fname[0] = 0;
如果您没有明确设置循环终止值,那么您之前的尝试很接近!对您的代码进行以下细微更改也应该有效:
fno.fname[0] = 1;
while (res == FR_OK && fno.fname[0]) {
res = f_readdir(&dj, &fno);
io->print((const char*)fno.fname);
io->print("\r\n");
}
但如果目录为空,它将打印一个空行。
老实说,ELM FatFs 的语义f_readdir()
有些奇怪。您可能会考虑使用包装器来为其提供更一致和传统的界面:
FRESULT readdir( DIR* dp, /* [IN] Directory object */
FILINFO* fno /* [OUT] File information structure */ )
{
FRESULT res = f_readdir( dp, fno ) ;
if( res == FR_OK && fno->fname[0] == 0 )
{
res = FR_NO_FILE ;
}
return res ;
}
然后你可以写(例如):
while( readdir( &dj, &fno ) == FR_OK )
{
io->print((const char*)fno.fname);
io->print("\r\n");
}
推荐阅读
- asp.net-core - ASP.NET Identity Core 2:根据登录 URL 添加自定义声明
- vba - 返回值后格式化报表文本框
- node.js - 管理 Node JS 依赖项
- c# - 二进制不能是主要的,但唯一不变的列是二进制
- angular - 未捕获的错误:为组件 AppComponent 指定的模板不是字符串
- swift - 淡入淡出UILabel,每次改变屏幕上的文字
- mysql - mysql 使用 IF NOT NULL 作为事务的一部分
- python - 如何在 DataFrame 的每一行上为两列添加 value_counts?
- java - Libgdx 无法确定 java 版本 11.0.1
- r - 最低固定每月付款代码不起作用 - 无限循环?