授人以魚不如授人以漁,目的不是爲了教會你具體項目開發,而是學會學習的能力。但願你們分享給你周邊須要的朋友或者同窗,說不定大神成長之路有博哥的奠定石。。。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文件系統屬於很是重要的一篇,但願讀者能夠認真理解使用。