一起玩儿物联网人工智能小车(ESP32)——64 SD卡中文件的操作方法

摘要:本文介绍SD卡中文件的操作方法

在前面介绍了SD开模块的基本使用方法,现在先来看一个简单的例子,一个是稳固一下之前介绍的知识,另一个是作为下边继续进行文件系统操作的基础。

在这个例子中,按照前一篇介绍的步骤完成SD卡读取的初始化,然后打印出其容量。具体的实现代码如下:

#include "SD.h"

#include "SPI.h"

#define SS 5

#define SCK 18

#define MISO 19

#define MOSI 23

void setup() {

  Serial.begin(115200);

  // SPIClass spi = SPIClass(VSPI);   // 自定义SPIClass

  // spi.begin(SCK,MISO,MOSI,SS);

  SPI.begin(SCK, MISO, MOSI, SS);

  // if (!SD.begin(SS, spi)) {        // 使用自己创建SPIClass初始化SD

  if (!SD.begin(SS)) {

    Serial.println("挂载卡失败!");

    return;

  }

  uint8_t cardType = SD.cardType();

  if (cardType == CARD_NONE) {

    Serial.println("无卡!");

    return;

  }

  Serial.print("卡类型: ");

  if (cardType == CARD_MMC) {

    Serial.println("MMC");

  } else if (cardType == CARD_SD) {

    Serial.println("SDSC");

  } else if (cardType == CARD_SDHC) {

    Serial.println("SDHC");

  } else {

    Serial.println("UNKNOWN");

  }

  uint64_t cardSize = SD.cardSize() / (1024 * 1024);

  Serial.printf("卡容量: %lluMB\n", cardSize);

}

void loop() {

  // put your main code here, to run repeatedly:

}

上面代码中,之前介绍的2中配置SPI引脚办法的代码都给了出来,可以根据自己的情况选择使用。该程序的执行结果如下图所示。

上面程序中的SD对象为SDFS类的实例,它是挂载SD卡后的句柄,通过它可以获得SD卡的基本信息,并且也包含了一些关于文件和目录的基本操作。具体如下所示:

方法

用途

begin(uint8_t ssPin=SS, SPIClass &spi=SPI,

 uint32_t frequency=4000000,

const char * mountpoint="/sd",

uint8_t max_files=5,

bool format_if_empty=false)

初始化并挂载SD卡

end()

卸载SD卡并释放资源

cardType()

返回卡的类型

cardSize()

返回卡容量的字节数

numSectors()

返回SD卡的扇区数

sectorSize()

返回SD卡的扇区大小

totalBytes()

返回SD卡的总空间

usedBytesBytes()

返回SD卡的已用空间大小

readRAW(uint8_t* buffer, uint32_t sector)

读取扇区数据

writeRAW(uint8_t* buffer, uint32_t sector)

写入扇区数据

open()

打开某个文件或者路径

exists()

判断某个文件或者路径是否存在

remove()

删除文件

rename()

修改文件名

mkdir()

创建目录

rmdir()

删除目录

显然SDFS类在文件操作上提供的方法是远远不够的,这就用到了另一个类File类,这个File类可以对文件和文件夹进行相关的操作,与大部分编程语言对于文件的操作方法基本一致。通过SDFS的open()方法可以返回一个File类的实例,该实例是所要操作的文件或者文件夹的句柄,然后可以对其进行相关操作。File类所包含的方法如下:

方法

用途

available()

返回还可以读取的字节数

write()

写入数据到文件

read()、readBytes()

从文件中读取数据

flush()

将缓存中的数据写入SD卡

peek()

读取一个字节的数据

seek()

改变文件读写位置

position()

返回当前读写位置

size()

返回文件的大小

setBufferSize()

设置文件流缓冲区大小

close()

关闭文件句柄

getLastWrite()

最后修改时间

path()

返回当前文件路径

name()

返回当前文件名

isDirectory()

判断是不是文件夹

seekDir()

用于改变当前访问文件夹中文件的位置

openNextFile()

打开文件夹中的下一个文件(文件夹)

getNextFileName()

返回文件夹中下一个文件(文件夹)名

rewindDirectory()

返回到目录中第一个文件(文件夹)

下面来看一个完整的例子,里面包括了创建、删除目录、列目录中的文件和文件夹、写入信息、追加信息到文件、从文件中读取信息、删除文件等常规操作。可以将这个程序作为样例保存着,以便到需要的时候可以查询一下。

#include "SD.h"

#include "SPI.h"

#define SS 5

#define SCK 18

#define MISO 19

#define MOSI 23

/**

 * 输出文件夹中的文件夹和文件

 */

void listDir(fs::FS &fs, const char *dirname, uint8_t levels) {

  Serial.printf("列表文件夹: %s\n", dirname);

  File root = fs.open(dirname);

  if (!root) {

    Serial.println("打开文件夹失败!");

    return;

  }

  if (!root.isDirectory()) {

    Serial.println("不是文件夹!");

    return;

  }

  File file = root.openNextFile();

  while (file) {

    if (file.isDirectory()) {

      Serial.print("  文件夹 : ");

      Serial.println(file.name());

      if (levels) {

        listDir(fs, file.path(), levels - 1);

      }

    } else {

      Serial.print("  文件: ");

      Serial.print(file.name());

      Serial.print("  大小: ");

      Serial.println(file.size());

    }

    file = root.openNextFile();

  }

}

void createDir(fs::FS &fs, const char *path) {

  Serial.printf("创建目录: %s\n", path);

  if (fs.mkdir(path)) {

    Serial.println("目录已创建!");

  } else {

    Serial.println("目录创建失败!");

  }

}

void removeDir(fs::FS &fs, const char *path) {

  Serial.printf("删除目录: %s\n", path);

  if (fs.rmdir(path)) {

    Serial.println("目录已删除!");

  } else {

    Serial.println("删除目录失败!");

  }

}

void readFile(fs::FS &fs, const char *path) {

  Serial.printf("读取文件: %s\n", path);

  File file = fs.open(path);

  if (!file) {

    Serial.println("打开文件失败!");

    return;

  }

  Serial.print("文件内容: ");

  while (file.available()) {

    Serial.write(file.read());

  }

  file.close();

}

void writeFile(fs::FS &fs, const char *path, const char *message) {

  Serial.printf("写入文件: %s\n", path);

  File file = fs.open(path, FILE_WRITE);

  if (!file) {

    Serial.println("打开写入文件失败!");

    return;

  }

  if (file.print(message)) {

    Serial.println("已经写入文件!");

  } else {

    Serial.println("写入文件失败!");

  }

  file.close();

}

void appendFile(fs::FS &fs, const char *path, const char *message) {

  Serial.printf("追加到文件: %s\n", path);

  File file = fs.open(path, FILE_APPEND);

  if (!file) {

    Serial.println("打开追加文件失败!");

    return;

  }

  if (file.print(message)) {

    Serial.println("内容已经追加!");

  } else {

    Serial.println("内容追加失败!");

  }

  file.close();

}

void renameFile(fs::FS &fs, const char *path1, const char *path2) {

  Serial.printf("修改文件 %s 成 %s\n", path1, path2);

  if (fs.rename(path1, path2)) {

    Serial.println("文件名称修改成功!");

  } else {

    Serial.println("重命名失败!");

  }

}

void deleteFile(fs::FS &fs, const char *path) {

  Serial.printf("删除文件: %s\n", path);

  if (fs.remove(path)) {

    Serial.println("文件已删除!");

  } else {

    Serial.println("删除文件失败!");

  }

}

void setup() {

  Serial.begin(115200);

  // SPIClass spi = SPIClass(VSPI);   // 自定义SPIClass

  // spi.begin(SCK,MISO,MOSI,SS);

  SPI.begin(SCK, MISO, MOSI, SS);

  // if (!SD.begin(SS, spi)) {        // 使用自己创建SPIClass初始化SD

  if (!SD.begin(SS)) {

    Serial.println("挂载卡失败!");

    return;

  }

  uint8_t cardType = SD.cardType();

  if (cardType == CARD_NONE) {

    Serial.println("无卡!");

    return;

  }

  Serial.print("卡类型: ");

  if (cardType == CARD_MMC) {

    Serial.println("MMC");

  } else if (cardType == CARD_SD) {

    Serial.println("SDSC");

  } else if (cardType == CARD_SDHC) {

    Serial.println("SDHC");

  } else {

    Serial.println("UNKNOWN");

  }

  uint64_t cardSize = SD.cardSize() / (1024 * 1024);

  Serial.printf("卡容量: %lluMB\n", cardSize);

  listDir(SD, "/", 0);

  createDir(SD, "/mydir");

  listDir(SD, "/", 0);

  removeDir(SD, "/mydir");

  listDir(SD, "/", 0);

  writeFile(SD, "/hello.txt", "Hello ");

  appendFile(SD, "/hello.txt", "World!\n");

  readFile(SD, "/hello.txt");

  deleteFile(SD, "/foo.txt");

  renameFile(SD, "/hello.txt", "/foo.txt");

  readFile(SD, "/foo.txt");

  Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));

  Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));

}

void loop() {

  // put your main code here, to run repeatedly:

}

使用到的方法在之前也都解释过了,并且每个函数都有大概的说明,在这里就不再进一步的解释了。

  • 33
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 结婚的小游戏有很多种,以下是一些可以玩的小游戏: 1. 谁更了解新郎/新娘:在游戏,新郎/新娘会回答一些问题,例如最喜欢的食物、最爱的电影等,然后参加游戏的人会猜测新郎/新娘的答案,看谁猜得最准。 2. 新婚猜谜:这个游戏需要准备一些有关新婚的谜语,让参加游戏的人猜测答案。 3. 找出新娘的鞋子:在婚礼上,新娘通常会穿上一双特别的婚鞋,游戏会将其藏起来,然后参加游戏的人需要找出新娘的鞋子,找到的人会获得奖励。 4. 谁抛的花束最远:在这个游戏,新娘会抛出她的花束,然后参加游戏的单身女性会尽可能远地抓住花束,抓到花束的人会成为下一个结婚的新娘。 5. 猜婚礼歌曲:在这个游戏,会播放一些与婚礼相关的歌曲,参加游戏的人需要猜出这些歌曲的名称或歌手。 ### 回答2: 结婚是一段充满喜悦和甜蜜的时刻,为了增添婚礼的欢乐氛围,可以进行一些有趣的小游戏。以下是一些结婚小游戏的建议: 1. 猜新娘:新郎闭上眼睛,由新娘和一些女性嘉宾站在一起,新郎需要摸出新娘,以测试他对新娘的认识。 2. 装扮新娘:将新娘的婚纱分成若干块,要求新郎将这些块组装回来,以检验他的耐心和对新娘外貌的记忆。 3. 感情真假:为每对新婚夫妇准备一些问题,让新郎和新娘轮流回答。问题可以涉及他们的未来计划、感情故事等,以检验他们对彼此了解的程度。 4. 隔空传情:准备一些纸板,新郎和新娘分别站在一段距离的两端,各自用嘴巴夹住纸板,然后通过用纸板传送信件或者吻信,以增加互动和竞争的乐趣。 5. 拍拖大作战:请一些单身朋友参与比赛,让他们模仿新郎和新娘的甜蜜动作或场景,由新郎和新娘评选最像的一对。 6. 献花传情:要求嘉宾们分成两队,每队选出一名代表,站在一段距离的两端。每名代表手持一朵花束,通过传递花束的方式,以最快的速度将花束传至对方代表手。 这些小游戏旨在加强新郎和新娘之间的默契和互动,同时给婚礼增添欢乐和独特的回忆。 ### 回答3: 结婚的小游戏有很多种,可以根据新娘和新郎的喜好、婚礼主题以及场地条件来选择。以下是一些常见的结婚小游戏: 1. 猜新娘或新郎的年龄、生肖、星座等:在婚宴上,主持人可以播放照片或简短视频,让宾客猜测新娘或新郎的基本信息,这样可以增加互动和欢乐氛围。 2. 问题游戏:新娘和新郎事先准备一些问题,让宾客回答,例如他们相识的地点、第一次约会的情景等等。这是一个有趣的互动环节,使宾客更了解新人的爱情故事。 3. 婚戒传递游戏:将新娘和新郎的婚戒放在一系列纸杯或袋子,宾客之间传递婚戒,最后由新郎把婚戒套在新娘的手指上。这是一个欢乐的游戏,可以增加气氛。 4. 玩转绳的游戏:让新郎和新娘手持一根绳子,游戏主持人念出一些有关新婚生活的情景,两人根据情景变化来调整绳子的形状。这个游戏考验新人的默契和协作能力。 5. 尬聊游戏:在宾客席上放置一些聊天题,例如“最难忘的一次旅行”、“最喜欢的一本书”等,让宾客自由交流。这样可以拉近宾客之间的距离,增加互动氛围。 总的来说,结婚的小游戏可以通过增加互动和娱乐性,使宾客更好地融入婚礼,与新人共享喜庆的氛围。当然还可以根据实际情况发挥创意,设计出更多有趣的结婚小游戏,以让婚礼更加精彩难忘。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一起玩儿科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值