赞
踩
前文中:https://blog.csdn.net/m0_50114967/article/details/126910392
已经创建了一个AP和STA模式共存的WEB服务器,在保存html网页代码时使用的是SPIFFS的文件系统,而不是更有效率的LittleFS文件系统,在之前已经简单地介绍了SPIFFS文件系统,在后续的WEB服务器的搭建里,将会更多地使用到ESP32的文件系统,比如保存或读取一些设置参数,这里会更详细地介绍SPIFFS文件系统,同时也会详细地介绍一下LittleFS文件系统。
在ESP32中使用闪存有两种文件系统,SPIFFS和LittleFS。
SPIFFS是比较原始的文件系统,支持静态和动态磨损均衡,没有目录系统,就是说所有文件都保存在根目录上。对于小文件比较多的情况下,对于内存空间的利用比较理想(最小256字节的分配)。
LittleFS是新增加的一种文件系统,性能方面比SPIFFS较高,带有目录系统,但对于小文件比较多的情况下,对于内存空间的利用更多(最小4K字节的分配)。
他们共享一套文件操作的兼容API,但对于闪存的操作并不兼容,在使用中,最好只选择其中一种。如果在SPIFFS下挂载LittleFS系统,可能会导致文件的丢失。反之也是一样。所以同一项目中,最不要两种系统混用。
虽然对于闪存的操作并不兼容,但在使用中所用的方法都是高度一致的。
目录
setTimeCallback(time_t(*cb)(void))
- SPIFFSConfig cfg;
- cfg.setAutoFormat(false);
- SPIFFS.setConfig(cfg);
默认情况下,如果文件系统挂载失败,会自动格式化文件系统。该方法将文件系统设置为禁用挂载失败时自动格式化文件系统。
挂载文件系统:
SPIFFS.begin()
对应
LittleFS.begin()
请注意,如果已经挂载了SPIFFS,又再挂载LittleFS,会丢失所有的在该系统上的所有文件。
卸载文件系统:
SPIFFS.end()
对应
LittleFS.end()
格式化文件系统:
SPIFFS.format()
对应
LittleFS.format()
打开文件
SPIFFS.open(path, mode)
对应
LittleFS.open(path, mode)
参数:
path: 字符串,文件所在的绝对路径
mode: 字符串,指定访问权限,可以是“r”、“w”、“a”、“r+”、“w+”、“a+”之一
r: 只读模式,文件流在文件开头。
r+: 读写模式,文件流在文件开头。
w: 写入模式,如果对应的文件已存在,会被清零并新建该文件,文件流在文件开头。
w+: 读写模式,如果文件不存在,则新建该文件,存在则会被清零,文件流在文件开头。
a: 追加模式,如果文件不存在,则新建该文件,文件流在文件结尾。
a+: 读取和追加模式,如果文件不存在,则新建该文件,在读取时,会从文件开头读取,但写入时会从文件结尾追加。
函数返回一个文件对象,用布尔值来检查文件是否被打开。
-
-
- File f = <SPIFFS or LittleFS>.open("/f.txt", "w");
- if (!f) {
- Serial.println("file open failed");
- }
检查文件是否存在,返回true或false
SPIFFS.exists(path)
对应
LittleFS.exists(path)
新建一个目录,成功返回true,失败返回false,SPIFFS没有目录系统
LittleFS.rmdir(path)
删除目录,成功返回true,失败返回flase,SPIFFS没有目录系统
LittleFS.rmdir(path)
打开一个目录,因为SPIFFS没有目录系统,所以会返回带有/字符的文件
SPIFFS.openDir(path)
对应
LittleFS.openDir(path)
删除文件,成功返回true,失败返回flase
SPIFFS.remove(path)
对应
LittleFS.remove(path)
重命名文件,pathFrom重命名为pathTo,路径都必须为绝对路径,成功返回true,失败返回false
SPIFFS.rename(pathFrom, pathTo)
对应
LittleFS.rename(pathFrom, pathTo)
只能用在SPIFFS系统,垃圾回收操作,可以使之后的写入更快
SPIFFS.gc()
只能用在SPIFFS系统,尝试修复文件系统,不能保证实际修复效果
- SPIFFS.begin();
- SPIFFS.check();
设置文件系统信息
- FSInfo fs_info;
- SPIFFS.info(fs_info);
- or LittleFS.info(fs_info);
文件系统信息结构:
- struct FSInfo {
- size_t totalBytes; //文件系统可用数据总大小
- size_t usedBytes; //文件使用的字节数
- size_t blockSize; //文件系统块的大小
- size_t pageSize; //文件系统逻辑页面大小
- size_t maxOpenFiles; //可同时打开的文件数
- size_t maxPathLength; //最大文件名长度(包知一个字节的\0终止符)
- };
与info的操作相同,但允许操作大于4GB的文件系统
setTimeCallback(time_t(*cb)(void))
设置文件时间戳的回调,
- time_t myTimeCallback() {
- return 1455451200;
- }
- void setup () {
- LittleFS.setTimeCallback(myTimeCallback);
- }
遍历目录中的文件:
- Dir dir = SPIFFS.openDir("/data");
- // or Dir dir = LittleFS.openDir("/data");
- while (dir.next()) {
- Serial.print(dir.fileName());
- if(dir.fileSize()) {
- File f = dir.openFile("r");
- Serial.println(f.size());
- }
- }
当目录中有文件时返回true
返回当前指向的文件的名称
返回当前指向的文件的大小
返回当前指向的文件的写入时间
返回当前指向的文件的创建时间
如果当前指向的文件是一个文件
如果当前指向的文件是一个目录
该方法和SPIFFS/LittleFS.open()一样的mode参数
将指针重置为目录的开头
设置时间戳的回调
文件对象
.open方法返回一个File对象,该对象支持Stream流
移动文件流的位置
file.seek(offset, mode);
参数:
offset: 偏移值
mode: 偏移位置设置
SeekSet: 从文件开始偏移offset
SeekCur: 从当前位置开始偏移offset
SeekEnd: 从文件末尾开始偏移offset
成功返回true,失败返回false
返回文件流的位置
file.position();
返回文件大小
file.size();
返回不带路径的文件名
String name = file.name();
返回包括目录的文件名
String name = file.fullName();
返回文件上次写入时间,仅对只读方式打开的文件有效,如果在写入模式,返回的时间是不确定的
time_t t=file.getLastWrite();
返回文件创建时间
time_t t=file.getCreationTime();
如果File指向文件,返回true
- if(file.isFile()) {
- Serial.println("这是一个文件");
- }else {
- Serial.println("这不是一个文件");
- }
如果File指向文件夹,返回true
- if(file.isDirectory()) {
- Serial.println("这是一个文件夹");
- }else {
- Serial.println("这不是一个文件夹");
- }
关闭文件
file.close();
读取一个字节(以二进制读取)的数据
Serial.println(file.read());
读取出的数据为ASCII的编码,比如文本文件内只保存有一个字符'a',读取出来的数据为'61'。对应的编码可以自行查找ASCII的编码表。
读取指定长度的数据
- size_t len = 20;
- char buffer[len];
- file.readBytes(buffer, len);
- Serial.print("FILE:");
- for(int i=0; i<len; i++){
- Serial.println(buffer[i]);
- }
读取指定长度或直到指定结束符的数据
- char terminateChar = 'x';
- size_t len = 20;
- char buffer[len];
- file.readBytesUntil(terminateChar,buffer, len);
- Serial.print("FILE:");
- for(int i=0; i<len; i++){
- Serial.println(buffer[i]);
- }
读取字符串
Serial.println(file.readString());
读取直到指定结束符的字符串
Serial.println(file.readStringUntil('\n'));
搜索指定字符串,找到指定字符串时退出函数并返回true
- if(file.find("x")) {
- Serial.print("Great! found "); Serial.println("x");
- } else {
- Serial.print("Sorry can't find "); Serial.println("x");
- }
搜索指字字符串,找到指定字符串时退出函数并返回true,读取到终止字符时退出函数并返回
- if(file.findUntil("x", "STOP")) {
- Serial.print("Great! found "); Serial.println("x");
- } else {
- Serial.print("Sorry can't find "); Serial.println("x");
- }
用于读取一个字节的数据。但是与read函数不同的是,使用peek函数读取数据后,被读取的数据不会从数据流中消除。这就导致每一次调用peek函数,只能读取数据流中的第一个字符。然而每一次调用read函数读取数据时,被读取的数据都会从数据流中删除
Serial.println(file.peek());
用于从读取到的的数据中寻找整数数值
Serial.print("FILE:");Serial.println(file.parseInt());
用于从读取到的的数据中寻找浮点数值
Serial.print("FILE:");Serial.println(file.parseFloat());
写入字符串
file.print();
println
写入一行字符串
file.println();
还有一些兼容的方法,不推荐使用,这里不作介绍。
以上翻译的说明来自官方对这两种文件系统介绍,可能会有所错漏
官方说明地址:https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#
以上说明可以证实,如果使用LittleFS文件系统,除了拥有目录系统,读取效率也更高,在官方说明中,也提示了SPIFFS将被弃用的警告,原文
SPIFFS Deprecation Warning
SPIFFS is currently deprecated and may be removed in future releases of the core. Please consider moving your code to LittleFS. SPIFFS is not actively supported anymore by the upstream developer, while LittleFS is under active development, supports real directories, and is many times faster for most operations.
ESPAsyncWebServer库虽然并未宣称支持LittleFS文件系统,但通过测试,可以发现ESPAsyncWebServer是可以使用LittleFS文件系统的。
LittleFS文件的上传,需要另外的arduino IDE插件,arduino-esp32fs-plugin,该插件可同时支持SPIFFS和LittleFS文件系统的上传,项目地址:
https://github.com/lorol/arduino-esp32fs-plugin
下载以下文件
把下载到的文件"esp32fs.jar"复制arduino安装目录下的<arduino>\tools\ESP32FS\tool文件夹下,如果文件夹不存在就新建一个。重启arduino IDE,如果安装成功,工具菜单下将出现如下选项:
点击就可以把项目文件夹下的data文件夹的所有文件上传到ESP32,注意上传前必须关闭"串口监视器"。
对应两个文件系统的区别,我们只要增加LittleFS的头文件引用和把使用SPIFFS的地方修改成使用LittleFS就可以了。修改后的代码:
- #include <WiFi.h>
- #include <LittleFS.h>
- #include <DNSServer.h>
- #include "ESPAsyncWebServer.h"
-
-
- DNSServer dnsserver;
- AsyncWebServer server(80);
-
- //连接WIFI
- void connect_wifi(){
- const byte DNS_PORT = 53; //DNS端口
- const String url = "ESPAP.com"; //域名
- IPAddress APIp(10,0,10,1); //AP IP
- IPAddress APGateway(10,0,10,1); //AP网关
- IPAddress APSubnetMask(255,255,255,0); //AP子网掩码
- const char* APSsid = "esp32_AP"; //AP SSID
- const char* APPassword = "12345678"; //AP wifi密码
-
- const char* wifi_ssid = "ESP32";
- const char* wifi_password = "12345678";
- Serial.begin(9600);
- WiFi.mode(WIFI_AP_STA); //打开AP和STA共存模式
- WiFi.softAPConfig(APIp, APGateway, APSubnetMask); //设置AP的IP地址,网关和子网掩码
- WiFi.softAP(APSsid, APPassword, 6); //设置AP模式的登陆名和密码
- dnsserver.start(DNS_PORT, url, APIp); //设置DNS的端口、网址、和IP
- WiFi.begin(wifi_ssid, wifi_password); //连接WIFI
- Serial.print("Connected");
- //循环,直到连接成功
- while(WiFi.status() != WL_CONNECTED){
- Serial.print(".");
- delay(500);
- }
- Serial.println();
- IPAddress local_IP = WiFi.localIP();
- Serial.print("WIFI is connected,The local IP address is "); //连接成功提示
- Serial.println(local_IP);
- }
-
- void web_server(){
- if(!LittleFS.begin(true)){
- Serial.println("An Error has occurred while mounting LittleFS");
- return;
- }
- server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html");
- server.begin(); //初始化
- }
-
- void setup() {
- connect_wifi();
- web_server();
- }
-
- void loop() {
- dnsserver.processNextRequest();
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。