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

本文详细介绍了如何在Arduino中使用SD卡,包括SD卡的初始化、检测类型、容量获取,以及通过SDFS和File类进行文件和目录的操作,如创建、删除、列出目录、读写文件等。
摘要由CSDN通过智能技术生成

摘要:本文介绍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:

}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一起玩儿科技

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

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

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

打赏作者

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

抵扣说明:

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

余额充值