授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力。但愿你们分享给你周边须要的朋友或者同窗,说不定大神成长之路有博哥的奠定石。。。css
QQ技术互动交流群:ESP8266&32 物联网开发 群号622368884,不喜勿喷html
1、基础篇java
2、网络篇git
- ESP8266开发之旅 网络篇① 认识一下Arduino Core For ESP8266
- ESP8266开发之旅 网络篇② ESP8266 工做模式与ESP8266WiFi库
- ESP8266开发之旅 网络篇③ Soft-AP——ESP8266WiFiAP库的使用
- ESP8266开发之旅 网络篇④ Station——ESP8266WiFiSTA库的使用
- ESP8266开发之旅 网络篇⑤ Scan WiFi——ESP8266WiFiScan库的使用
- ESP8266开发之旅 网络篇⑥ ESP8266WiFiGeneric——基础库
- ESP8266开发之旅 网络篇⑦ TCP Server & TCP Client
- ESP8266开发之旅 网络篇⑧ SmartConfig——一键配网
- ESP8266开发之旅 网络篇⑨ HttpClient——ESP8266HTTPClient库的使用
- ESP8266开发之旅 网络篇⑩ UDP服务
- ESP8266开发之旅 网络篇⑪ WebServer——ESP8266WebServer库的使用
- ESP8266开发之旅 网络篇⑫ 域名服务——ESP8266mDNS库
- ESP8266开发之旅 网络篇⑬ SPIFFS——ESP8266 Flash文件系统
- ESP8266开发之旅 网络篇⑭ web配网
- ESP8266开发之旅 网络篇⑮ 真正的域名服务——DNSServer
- ESP8266开发之旅 网络篇⑯ 无线更新——OTA固件更新
3、应用篇github
4、高级篇web
在前面博文关于ESP8266WiFiWebServer的例程中,你们能够发现,博主基本上都是手动拼装html内容返回,html的内容被固定写在咱们的Arduino ESP代码中。
那么这样就有两点弊端:服务器
基于以上两点弊端,正式引入本篇章须要研究的ESP8266 文件系统(SPI Flash FileSystem,简称为SPIFFS)。网络
先来看一个概念图:ide
这个文件系统能够帮助咱们存储一些变动频率不频繁的文件例如网页、配置或者是某些固化的数据等。
其实,咱们用得更多的是存储网页,将网页和相关资源(如:图片、html、css、javaScript)存入到flash的SPIFFS区域。
原理以下图:
函数
在讲解SPIFFS以前,咱们来看看在Arduino环境下ESP8266的flash存储分配,请看下图:
具体能够分为几部分:
即便文件系统与程序存储在同一个闪存芯片上,烧入新的代码也不会修改文件系统内容。这容许使用文件系统来存储Web服务器的代码数据、配置文件或内容。而这个SPIFFS文件系统的大小能够经过烧写环境来配置,目前通常有1M,2M,3M等等。博主建议若是是NodeMcu板子,能够配置成3M;
为了使用文件系统,须要把下面的头文件包含在代码中:
#include <FS.h>
ESP8266的文件系统实现必须知足芯片的限制,其中最重要是有限的RAM。SPIFFS之因此被ESP8266选择做为文件系统,是由于它是为小型系统专门设计的,同时是以一些简化和限制为代价的。
首先,SPIFFS不支持目录,它只存储一个“扁平化”的文件列表。可是与传统的文件系统相反,斜杠字符“/”在文件名中是容许的,所以处理目录列表的函数(例如,openDir("/website"))基本上只是过滤文件名,并保留之前缀(/website/)开始的那些文件。
而后,对于文件名,总共有32个字符限制。一个“\0”字符被保留用于c字符串终止符,所以留给咱们31个可用字符长度。
综合起来,这意味着建议保持短文件名,不要使用深嵌套的目录,由于每一个文件的完整路径(包括目录、“/”字符、基本名称、点和扩展名)最多只能是31个字符长度。例如,/website/images/bird_thumbnail.jpg 达到了34个字符长度,若是使用它,将致使一些问题。
警告:这个限制很容易达到,若是忽略,问题可能会被忽略,由于在编译和运行时不会出现错误信息。
使用文件系统目的就是为了存储文件,那么存储文件的方式其实能够分为3种:
本质上,不管是经过ESP8266FS或者OTA Update的方式把文件上传到SPIFFS,其底层都是经过调用FS提供的API去完成,因此咱们只须要了解FS经常使用API便可。
了解一下SPIFFS文件系统经常使用的操做方法,如下是博主总结的百度脑图:
方法分为3大类:
函数说明:
/** * 挂载SPIFFS文件系统 * @return bool 若是文件系统挂载成功,返回true,不然返回false */ bool begin();
注意点:
函数说明:
/** * 格式化文件系统 * @return bool 若是格式化成功则返回true */ bool format();
注意点:
函数说明:
/** * 打开文件,某种模式下会建立文件 * @param path 文件路径 * @param mode 存取模式 * @return File 返回一个File对象 */ File open(const char* path, const char* mode); File open(const String& path, const char* mode);
注意点:
若是要检查文件是否打开成功,请使用如下代码:
File f = SPIFFS.open("/f.txt", "w"); if (!f) { Serial.println("file open failed"); }
函数说明:
/** * 路径是否存在 * @param path 文件路径 * @return bool 若是指定的路径存在,则返回true,不然返回false */ bool exists(const char* path); bool exists(const String& path);
函数说明:
/** * 打开绝对路径文件夹 * @param path 文件路径 * @return Dir 打开绝对路径文件夹,返回一个Dir对象 */ Dir openDir(const char* path); Dir openDir(const String& path);
函数说明:
/** * 删除绝对路径的文件 * @param path 文件路径 * @return bool 若是删除成功则返回true,不然返回false */ bool remove(const char* path); bool remove(const String& path);
函数说明:
/** * 从新命名文件 * @param pathFrom 原始路径文件名 * @param pathTo 新路径文件名 * @return bool 若是从新命名成功则返回true,不然返回fals */ bool rename(const char* pathFrom, const char* pathTo); bool rename(const String& pathFrom, const String& pathTo);
函数说明:
/** * 获取文件系统的信息,存储在FSInfo对象 * @param info FSInfo对象 * @return bool 是否获取成功 */ bool info(FSInfo& info);
FSInfo定义以下:
struct FSInfo { size_t totalBytes;//整个文件系统的大小 size_t usedBytes;//文件系统全部文件占用的大小 size_t blockSize;//SPIFFS块大小 size_t pageSize;//SPIFFS逻辑页数大小 size_t maxOpenFiles;//可以同时打开的文件最大个数 size_t maxPathLength;//文件名最大长度(包括一个字节的字符串结束符) };
在上面的方法中,咱们能够获取到Dir对象,那么看看Dir对象定义是什么?
class Dir { public: Dir(DirImplPtr impl = DirImplPtr()): _impl(impl) { } File openFile(const char* mode);//打开文件 String fileName();//获取文件名字 size_t fileSize();//文件大小 bool next();//下一个文件 protected: DirImplPtr _impl; };
注意点:
函数说明:
/** * 打开文件 * @param mode 打开模式,请参考open方法 * @return File 返回一个File对象 */ File openFile(const char* mode);
函数说明:
/** * 获取文件大小 * @return size_t 文件大小 */ size_t fileSize();
函数说明:
/** * 是否还有下一个文件 * @return bool true 表示还有文件 */ bool next();
注意点:
那么,咱们来看看File对象结构:
class File : public Stream { public: File(FileImplPtr p = FileImplPtr()) : _p(p) {} // Print methods: size_t write(uint8_t) override; size_t write(const uint8_t *buf, size_t size) override; // Stream methods: int available() override; int read() override; int peek() override; void flush() override; size_t readBytes(char *buffer, size_t length) override { return read((uint8_t*)buffer, length); } size_t read(uint8_t* buf, size_t size); bool seek(uint32_t pos, SeekMode mode); bool seek(uint32_t pos) { return seek(pos, SeekSet); } size_t position() const; size_t size() const; void close(); operator bool() const; const char* name() const; protected: FileImplPtr _p; };
File对象支持Stream的全部方法,所以可使用readBytes、findUntil、parseInt、printIn以及其余stream方法。如下是File对象特有的一些方法:
函数说明:
/** * 设置文件位置偏移 * @param pos 偏移量 * @param mode 偏移模式 * @return bool 若是移动成功,则返回true,不然返回false */ bool seek(uint32_t pos, SeekMode mode); bool seek(uint32_t pos) { return seek(pos, SeekSet); }
注意点:
函数说明:
/** * 返回目前在文件中的位置 * @return size_t 当前位置 */ size_t position();
函数说明:
/** * 返回文件大小 * @return size_t 文件大小 */ size_t size();
函数说明:
/** * 返回文件名字 * @return const char* 文件名字 */ const char* name();
函数说明:
/** * 关闭文件 */ void close();
注意点:
实例说明:
spiffs文件操做常见方法使用,包括文件查找、建立、打开、关闭、删除
实例源码:
/** * 功能描述:spiffs文件操做常见方法使用,包括文件查找、建立、打开、关闭、删除 */ #include <FS.h> //如下三个定义为调试定义 #define DebugBegin(baud_rate) Serial.begin(baud_rate) #define DebugPrintln(message) Serial.println(message) #define DebugPrint(message) Serial.print(message) #define myFileName "mydemo.txt" void setup(){ DebugBegin(9600); DebugPrintln("Check Start SPIFFS..."); //启动SPIFFS,若是下载配置没有配置SPIFFS,返回false if(!SPIFFS.begin()){ DebugPrintln("Start SPIFFS Failed!please check Arduino Download Config."); return; } DebugPrintln("Start SPIFFS Done."); //判断文件是否存在 if(SPIFFS.exists(myFileName)){ DebugPrintln("mydemo.txt exists."); }else{ DebugPrintln("mydemo.txt not exists."); } File myFile; //打开文件 不存在就建立一个 可读可写 myFile = SPIFFS.open(myFileName,"w+"); //关闭文件 myFile.close(); //再次判断文件是否存在 if(SPIFFS.exists(myFileName)){ DebugPrintln("mydemo.txt exists."); }else{ DebugPrintln("mydemo.txt not exists."); } //删除文件 DebugPrintln("mydemo.txt removing..."); SPIFFS.remove(myFileName); //再次判断文件是否存在 if(SPIFFS.exists(myFileName)){ DebugPrintln("mydemo.txt exists."); }else{ DebugPrintln("mydemo.txt not exists."); } } void loop(){ }
实验结果:
实例说明:
查看spiffs文件系统列表
实例准备:
实例源码:
/** * 功能描述:查看spiffs文件系统列表 */ #include <FS.h> //如下三个定义为调试定义 #define DebugBegin(baud_rate) Serial.begin(baud_rate) #define DebugPrintln(message) Serial.println(message) #define DebugPrint(message) Serial.print(message) void setup(){ DebugBegin(9600); DebugPrintln("Check Start SPIFFS..."); //启动SPIFFS,若是下载配置没有配置SPIFFS,返回false if(!SPIFFS.begin()){ DebugPrintln("Start SPIFFS Failed!please check Arduino Download Config."); return; } DebugPrintln("Start SPIFFS Done."); File myFile; //打开文件 不存在就建立一个 可读可写 myFile = SPIFFS.open("/myDemo.txt","w+"); //关闭文件 myFile.close(); //打开文件 不存在就建立一个 可读可写 myFile = SPIFFS.open("/myDemo.jpg","w+"); //关闭文件 myFile.close(); //打开文件 不存在就建立一个 可读可写 myFile = SPIFFS.open("/myDemo.html","w+"); //关闭文件 myFile.close(); Dir dir = SPIFFS.openDir("/"); while(dir.next()){ String fileName = dir.fileName(); size_t fileSize = dir.fileSize(); Serial.printf("FS File:%s,size:%d\n",fileName.c_str(),fileSize); } DebugPrintln("Setup Done!"); } void loop(){ }
实验结果:
实例说明:
往文件myDemo.txt中写入“单片机菜鸟博哥666”并读取出来显示。
实例源码:
/** * 功能描述:演示文件读写功能 */ #include <FS.h> //如下三个定义为调试定义 #define DebugBegin(baud_rate) Serial.begin(baud_rate) #define DebugPrintln(message) Serial.println(message) #define DebugPrint(message) Serial.print(message) void setup(){ DebugBegin(9600); DebugPrintln("Check Start SPIFFS..."); //启动SPIFFS,若是下载配置没有配置SPIFFS,返回false if(!SPIFFS.begin()){ DebugPrintln("Start SPIFFS Failed!please check Arduino Download Config."); return; } DebugPrintln("Start SPIFFS Done."); File myFile; //打开文件 不存在就建立一个 可读可写 myFile = SPIFFS.open("myDemo.txt","w+"); if(myFile){ DebugPrintln("Writing something to myDemo.txt..."); myFile.println("单片机菜鸟博哥666"); myFile.close(); DebugPrintln("Writing Done."); }else{ DebugPrintln("Open File Failed."); } //打开文件 可读 myFile = SPIFFS.open("myDemo.txt","r"); if(myFile){ DebugPrintln("Reading myDemo.txt..."); while(myFile.available()){ //读取文件输出 Serial.write(myFile.read()); } myFile.close(); }else{ DebugPrintln("Open File Failed."); } DebugPrintln("Setup Done!"); } void loop(){ }
实验结果:
实验说明:
在上面的例子中,咱们都是本身手动在SPIFFS文件系统中建立或者写入文件,可是对于习惯web开发的人员来讲,确定是直接把写好的web程序(html、css、js、资源文件等)直接烧入文件系统更加使人容易接受。因此本例子主要是讲解如何往SPIFFS里面烧写文件。
这个例子是重点,由于绝大部分的web开发(web配网、web页面等)都是经常使用烧写文件的方式,请读者仔细阅读。
要存入SPIFFS区域的文件,都得事先放在代码目录里的“data”目录(请自行新增“data”目录)。
例如,存在一个项目工程叫作espStaticWeb,其文件结构以下:
负责将文件上传到SPIFFS的工具叫作 ESP8266FS。ESP8266FS是一个集成到Arduino IDE中的工具,它将一个菜单项添加到工具菜单,用于将skench data目录的内容上传到ESP8266 Flash文件系统中。
这个工具须要另外安装,整个上传文件步骤以下:
而后就会开始上传文件到ESP8266 flash文件系统。
当IDE显示“SPIFFS Image Uploaded”,表明上传完毕。
那么接下来讲明一下本例子内容:
{"name":"esp8266","flash":"QIO","board":"NodeMcu"}
实验准备:
实验源码:
/** * 功能描述:演示上传文件并读取文件内容 * 前提:须要先往SPIFFS里面上传config.txt文件 */ #include <FS.h> //如下三个定义为调试定义 #define DebugBegin(baud_rate) Serial.begin(baud_rate) #define DebugPrintln(message) Serial.println(message) #define DebugPrint(message) Serial.print(message) void setup(){ DebugBegin(9600); DebugPrintln("Check Start SPIFFS..."); //启动SPIFFS,若是下载配置没有配置SPIFFS,返回false if(!SPIFFS.begin()){ DebugPrintln("Start SPIFFS Failed!please check Arduino Download Config."); return; } DebugPrintln("Start SPIFFS Done."); File myFile; //打开文件 不存在就建立一个 可读可写 myFile = SPIFFS.open("/config.txt","r"); if(myFile){ //打印文件大小 int size = myFile.size(); Serial.printf("Size=%d\r\n", size); //读取文件内容 DebugPrintln(myFile.readString()); myFile.close(); DebugPrintln("Reading Done."); }else{ DebugPrintln("Open File Failed."); } } void loop(){ }
实验结果:
SPIFFS文件系统属于很是重要的一篇,但愿读者能够认真理解使用。