赞
踩
摘要:本文介绍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: } |
使用到的方法在之前也都解释过了,并且每个函数都有大概的说明,在这里就不再进一步的解释了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。