0

我的目标是能够浏览 SD 卡上的文件系统并挑选出某些文件类型并将它们显示给用户。当我sd.ls(LS_R)在 SdFat 库上执行时,它显示了很多隐藏文件。我可以很好地处理其中的大多数,但其中一些让我头疼。由于该库使用 8.3 命名约定,它会截断太长的文件/文件夹名称并用“~”替换它。这是一个问题,因为那时我无法区分可见的文件/文件夹和隐藏的文件/文件夹。有没有已知的方法来解决这个问题?

这是我的代码:

#include <SdFat.h>

const uint8_t chipSelect = 10;

SdFat sd;
SdFile file;

void setup() 
{
    Serial.begin(9600);
    while (!Serial) {} // wait for Leonardo
    delay(1000);

    if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();

    sd.ls(LS_R);
    while(1);
}

void loop() {}

这是我的“可见”文件系统:

Folder1/
    test3.txt
    test4.txt
Folder2/
BearsOutside/
test1.txt
test2.txt
LongFilename.txt

这是输出:

FOLDER1/
  TEST4.TXT
  TEST3.TXT
TEST2.TXT
~1.TRA
TEST1.TXT
TRASHE~1/
SPOTLI~1/
  STORE-V2/
    F8D581~1/
      PSID.DB
      TM~1.SNO
      TM~1.LIO
      LIO~1.CRE
      TMP.CAB
      CA~1.CRE
      INDEXS~1
      ~1.IND
      ~~2.IND
      ~~~3.IND
      ~~~~4.IND
      ~~~~~5.IND
      ~~~~~~34.IND
      ~~~~~~37.IND
      ~~~~~~40.IND
      ~~~~~~43.IND
      ~~~~~~46.IND
      ~~~~~~48.IND
      ~1.DIR
      LIVE~~~4.IND
      LIVE~~2.IND
      LIVE~~~3.IND
      LIVE~~~5.IND
      LIVE~~66.IND
      LIVE~~69.IND
      LIVE~~73.IND
      LIVE~1.SHA
      LIVE~~79.IND
      LIVE~1.DIR
      LIVE0D~1.SHA
      STORE.DB
      STOR~1.DB
      REVERS~1
      TMPSPO~1.STA
      PERMST~1
      STORE_~1
      JOURNA~1.LIV/
      JOURNA~2.LIV/
        RETIRE.3
      JOURNA~3.LIV/
        RETIRE.4
      JOURNA~4.LIV/
      JOURNA~1.ASS/
      JOURNA~2.ASS/
      JOURNA~1.HEA/
      JOURNA~1.MIG/
      JOURNA~2.MIG/
      JOURNA~1
      JOURNA~1.SCA/
        RETIRE.11
      REVERS~1.SHA
      ~1.SHA
      SHUTDO~1
      JOURNA~1.REP/
      CA~1.MOD
      LIVE~155.IND
      LIVE~158.IND
      0DIREC~1.SHA
      ~~~~~166.SHA
      LIVE~169.IND
      LIVE~172.IND
      LIVE~175.IND
      LIVE~178.IND
      LIVE~181.IND
      LIVE~184.IND
      LIVE~1.IND
      LIVE~190.IND
      LIVE~194.SHA
      STOR~1.UPD
      REVERS~1.UPD
      LIVE~202.IND
      TMPSPO~1.LOC
      LIVE~208.IND
      LIVE~211.IND
      LIVE~215.IND
      LIVE~218.SHA
      LIVE~~2.DIR
      LIVE1D~1.SHA
      LIVE~264.SHA
      LIVE~267.IND
      LIVE~270.IND
      LIVE~274.IND
      LIVE~277.IND
      LIVE~~~3.DIR
      LIVE~~2.SHA
      LIVE~~~3.SHA
      LIVE~~~4.SHA
      LIVE~~~5.SHA
      LIVE~296.SHA
      LIVE~300.SHA
      LIVE2D~1.SHA
      LIVE~308.SHA
      LIVE~327.IND
  STORE-V1/
    VOLUME~1.PLI
  VOLUME~1.PLI
FOLDER2/
BEARSO~1/
LONGFI~1.TXT

所以我的问题是,如何区分BEARSO~1/未隐藏的 [BearsOutside] 和隐藏的 [BearsOutside] SPOTLI~1/

4

3 回答 3

1

这些文件是由 Mac OSX 系统自动创建的……您可以选择不在任何 Mac 上插入 SD 卡吗?这将解决您的问题... ;-)

您也可以尝试使用 Mac 上的终端删除它们。

于 2014-02-12T18:53:02.020 回答
0

不幸的是,一些原始功能不能直接使用

SdFat sd;

目的。因此排除了使用“ls”功能。下面的代码应该完成你想要的。它将sd对象当前文件传递给指针p的目录条目对象。然后可以对其属性进行测试,以查看它们是否隐藏或其他。

请注意,有一种方法可以测试目录条目是否为长名称。但是,我不相信该条目正在缓存长名称本身。

下面确实编译。其中 99.5 来自我使用的工作代码。我已经添加了属性和长文件名检测,所以它应该可以工作。

void ListFiles2(uint8_t flags) {
  // This code is just copied from SdFile.cpp in the SDFat library
  // and tweaked to print to the serial output in html!
  dir_t p;

  sd.vwd()->rewind();
  Serial.println();
  while (sd.vwd()->readDir(&p) > 0) {
    // done if past last used entry
    if (p.name[0] == DIR_NAME_FREE) break;

    // skip deleted entry and entries for . and  ..
    if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue;

    // only list subdirectories and files
    if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;

    if ((p.attributes & DIR_ATT_HIDDEN) != DIR_ATT_HIDDEN) continue;

    // print any indent spaces
    Serial.print(F("  "));
    for (uint8_t i = 0; i < 11; i++) {
      if (p.name[i] == ' ') continue;
      if (i == 8) {
        Serial.print('.');
      }
      Serial.print((char)p.name[i]);
    }
    Serial.print(F(" "));

    // print file name with possible blank fill
    for (uint8_t i = 0; i < 11; i++) {
      if (p.name[i] == ' ') continue;
      if (i == 8) {
        Serial.print('.');
      }
      Serial.print((char)p.name[i]);
      if (DIR_IS_LONG_NAME(&p)) {
        Serial.print(F(" long fn"));
      }
    }

    if (DIR_IS_SUBDIR(&p)) {
      Serial.print('/');
    }

    // print modify date/time if requested
    if (flags & LS_DATE) {
      sd.vwd()->printFatDate(p.lastWriteDate);
      Serial.print(' ');
      sd.vwd()->printFatTime(p.lastWriteTime);
    }
    // print size if requested
    if (!DIR_IS_SUBDIR(&p) && (flags & LS_SIZE)) {
      Serial.print(' ');
      Serial.print(p.fileSize);
    }
    Serial.println();
  }
  Serial.println();
}
于 2014-02-03T19:09:33.830 回答
0

这是一个非常古老的问题,但它在谷歌搜索中排名很高,所以我将提供一些更新信息:

截至撰写本文时(2020 年秋季),存在对 SdFat 的重大升级。SdFat-2.0 已经推出好几年了,尽管它仍然被标记为 beta.8(并且在自述文件中被称为“早期 beta”),但已知问题相对较少,并且它在许多地方都在生产中使用网站。

我最初对采用它犹豫不决,但它提供了非常需要的新功能,最终我咬紧牙关接受了它。事实证明,它非常易于集成且非常稳定。

SdFat-2.0 包括对 ExFat 卷、长文件名和文件簇的预分配的强大支持,并具有确保对 SD 卡进行非阻塞写入的机制。这解决了长期存在的问题,即偶尔阻塞长写入延迟,该延迟曾经干扰 SD 卡上的数据记录。对于 ExFat 卷,自动处理预分配文件空间的最终截断的数据大小计算。

SdFat-2.0 支持多个卡,即使它们运行在不同的总线或不同的总线类型上。我有一个带有三张 SD 卡的设备,一张由 SDIO 寻址,另外两张在不同的 SPI 总线上运行,我可以毫无困难地复制文件。

AFAIK 与旧的 arduino <sd.h> 库只有两个不兼容,许多其他库依赖于这些库:

SDFat-2.0 使用新语法 forbegin(),传递一个配置对象,该对象告诉您 SD 卡的连接方式以及应如何寻址。

SdFat-2.0 不支持旧file.name()功能,因为它是为 8.3 文件名设置的。相反,您通过传递指向可以存储文件名的某个位置的 const char* 来获得长文件名。您需要完整的文件名才能打开文件,但如果您可以坚持使用 8.3 文件名,那么您可以创建一个实现简单无参数begin()和旧name()函数的包装器。这将使一切完全兼容sd.h并避免#ifdef对库进行任何修补。

这确实是我发现的唯一兼容性问题,而且我个人还没有遇到任何错误。你可以在这里找到 github 项目:github.com/greiman/SdFat-beta

于 2020-09-04T20:38:44.643 回答