文章目录[隐藏]
LVGL 有一个“文件系统”抽象模块,使您能够附加任何类型的文件系统。 文件系统由驱动器号标识。 例如,如果 SD 卡与字母“S”相关联,则可以访问类似“S:path/to/file.txt”的文件。
官方提供了“文件系统”抽象模块,用于上层GUI来读取文件,图片,字体等操作。你可以像使用FatFS一样使用LVGL的文件系统API,在LVGL使用外部存储设备的资源时会被自动调用,例如下面列出的都是LVGL的函数,对接文件系统后,这些函数会自动读取文件系统中的文件,只要添加其对应的解码库即可实现图片的显示
扩展文章:
ESP32开发学习 LVGL Littlevgl 使用文件系统加载PNG解码显示
LVGL Littlevgl 解码显示JPG图片三种方式JPG_SJPG_C Array
lv_img_set_src(img, "P:lv_lib_lodepng/png_decoder_test.png");
lv_img_set_src(img2, "S.\\lv_lib_split_jpg\\example\\images\\small_image.sjpg");
lv_img_set_src(img, "S/path/to/image.bmp");
lv_obj_t * img = lv_gif_create_from_file(parent, "S/path/to/example.gif");
本文开发环境:
Visual Studio Code V1.58.2
LVGL版本 V7.10.0
芯片平台:ESP32
IDF库版本:4.3.0
IDF TOOLS编译工具链版本:2.9
本文软件基于LVGL官方提供的ESP32工程lv_port_esp32修改而来
LVGL ESP32官方地址:https://github.com/lvgl/lv_port_esp32
开发板平台基于HelloBug ESP32开发板
开发板购买链接:https://hellobug.taobao.com/
一、lvgl文件系统接口移植
LVGL官方的ESP32项目中是没有接口代码的,但在官方git可以下载到。
地址:https://github.com/lvgl/lv_fs_if
下载后直接复制到项目工程中的components文件夹中。目录结构如下
光复制接口文件还不行,要把它作为LVGL的一个模块,还要编写添加一个CMakeLists.txt放在lv_fs_if文件夹下,内容和目录结构如下:
包含此文件夹下所有.c文件,另外引用idf库中的文件系统和底层SD卡驱动部分,将lv_fs_if注册到idf组件,最后添加两个需要用到的组件lvgl和my_sd_fatfs组件,lvgl都知道是LVGL的核心组件,my_sd_fatfs看名字就知道是自己写的,用来初始化SD卡底层并挂载底层的文件系统,这个怎么写后面会讲到。
二、修改配置
打开工程目录中LVGL目录中的lv_conf.h。\components\lvgl\lv_conf.h,在.h文件中最后添加如下配置来启用LVGL的文件系统
// File system interface
#define LV_USE_FS_IF 1
#if LV_USE_FS_IF
#define LV_FS_IF_FATFS 'S'
#define LV_FS_IF_PC '\0'
#define LV_FS_IF_POSIX '\0'
#endif
三、初始化底层SD卡驱动
要对接lvgl的文件系统,必须先初始化底层的存储器初始化及挂载文件系统。
在工程目录components中创建一个文件夹my_sd_fatfs,名字你们随便起,意思为初始化底层FATFS的源码目录,然后再其中再创建include文件夹,接着创建CMakeLists.txt,component.mk,my_sd_fatfs.c,my_sd_fatfs.h,文件夹结构如下:
CMakeLists.txt文件主要为这个组件添加文件和其它组件包含,其内容如下:
set(mysrcs "my_sd_fatfs.c")
idf_component_register(SRCS "${mysrcs}"
INCLUDE_DIRS "include"
REQUIRES fatfs)
component.mk文件内容
COMPONENT_ADD_INCLUDEDIRS := include
COMPONENT_SRCDIRS := .
my_sd_fatfs.h文件内容
#ifndef MY_SD_FATFS_H
#define MY_SD_FATFS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include "esp_vfs_fat.h"
#include "driver/sdspi_host.h"
#include "driver/spi_common.h"
#include "sdmmc_cmd.h"
#include "driver/sdmmc_host.h"
void SD_Fatfs_Init(void);
#endif /* LVGL_HELPERS_H */
my_sd_fatfs.c文件内容:
#include "my_sd_fatfs.h"
static const char *TAG = "TFCardFat";
#define MOUNT_POINT "/sdcard" // 第一个字节必须是‘/’
#define SPI_DMA_CHAN 2
//在测试SD和SPI模式时,请记住,一旦在SPI模式下初始化了卡,在不接通卡电源的情况下就无法在SD模式下将其重新初始化。
#define PIN_NUM_MISO 19
#define PIN_NUM_MOSI 23
#define PIN_NUM_CLK 18
#define PIN_NUM_CS 5
static void get_fatfs_usage(size_t* out_total_bytes, size_t* out_free_bytes);
void SD_Fatfs_Init(void)
{
esp_err_t ret; // ESP错误定义
sdmmc_card_t* card; // SD / MMC卡信息结构
const char mount_point[] = MOUNT_POINT; // 根目录
char ReadFileBuff[64];
esp_vfs_fat_sdmmc_mount_config_t mount_config = { // 文件系统挂载配置
.format_if_mount_failed = false, // 如果挂载失败:true会重新分区和格式化/false不会重新分区和格式化
.max_files = 5, // 打开文件最大数量
.allocation_unit_size = 16 * 1024
};
ESP_LOGI(TAG,"->Initializing SD card");
ESP_LOGI(TAG,"->Using SPI peripheralr");
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
spi_bus_config_t bus_cfg = {
.mosi_io_num = PIN_NUM_MOSI,
.miso_io_num = PIN_NUM_MISO,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4 * 1024 * sizeof(uint8_t),
};
host.slot = 2;
// SPI总线初始化
ret = spi_bus_initialize(host.slot, &bus_cfg, SPI_DMA_CHAN);
if (ret != ESP_OK) {
printf("%s->Failed to initialize bus.\r\n",TAG);
return;
}
// 这将初始化没有卡检测(CD)和写保护(WP)信号的插槽。
// 如果您的主板有这些信号,请修改slot_config.gpio_cd和slot_config.gpio_wp。
sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();// SPI2_HOST 1
slot_config.gpio_cs = PIN_NUM_CS;
slot_config.host_id = host.slot;
// 挂载文件系统
ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
printf("%s->Failed to mount filesystem.%s\r\n",TAG,
"If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
} else {
printf("%s->Failed to initialize the card %s (%s). ",TAG,
"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
}
return;
}
// TF卡已经初始化,打印TF卡属性
sdmmc_card_print_info(stdout, card);
// Print FAT FS size information
size_t bytes_total, bytes_free;
get_fatfs_usage(&bytes_total, &bytes_free);
printf("%s->FAT FS Total: %d MB, Free: %d MB \r\n",TAG, bytes_total / 1024, bytes_free / 1024);
}
此时使用使用POSIX和C标准库函数其实已经可以进行SD卡的文件进行各种操作了,接下来就是把C标准函数与LVGL的文件系统函数做一个对接。
四、对接文件操作函数
LVGL的文件操作函数在components\lvgl\lvgl\src\lv_misc\lv_fs.h文件中有定义,这里把大概要对接的函数列出如下:(这个文件不要修改!!)
lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode);
lv_fs_res_t lv_fs_close(lv_fs_file_t * file_p);
lv_fs_res_t lv_fs_remove(const char * path);
lv_fs_res_t lv_fs_read(lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br);
lv_fs_res_t lv_fs_write(lv_fs_file_t * file_p, const void * buf, uint32_t btw, uint32_t * bw);
lv_fs_res_t lv_fs_seek(lv_fs_file_t * file_p, uint32_t pos);
lv_fs_res_t lv_fs_tell(lv_fs_file_t * file_p, uint32_t * pos);
lv_fs_res_t lv_fs_trunc(lv_fs_file_t * file_p);
lv_fs_res_t lv_fs_size(lv_fs_file_t * file_p, uint32_t * size);
lv_fs_res_t lv_fs_rename(const char * oldname, const char * newname);
lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path);
lv_fs_res_t lv_fs_dir_read(lv_fs_dir_t * rddir_p, char * fn);
lv_fs_res_t lv_fs_dir_close(lv_fs_dir_t * rddir_p);
lv_fs_res_t lv_fs_free_space(char letter, uint32_t * total_p, uint32_t * free_p);
char * lv_fs_get_letters(char * buf);
const char * lv_fs_get_ext(const char * fn);
char * lv_fs_up(char * path);
const char * lv_fs_get_last(const char * path);
其实不用所的函数都实现对接,实现最常用的即可。我随便看看一个lv文件操作的函数是怎么一步一步调用到底层的。如components\lvgl\lvgl\src\lv_misc\lv_fs.c中lv_fs_open函数,原型如下:(此文件不要修改)
lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode)
{
file_p->drv = NULL;
file_p->file_d = NULL;
if(path == NULL) return LV_FS_RES_INV_PARAM;
char letter = path[0];
file_p->drv = lv_fs_get_drv(letter);
if(file_p->drv == NULL) {
return LV_FS_RES_NOT_EX;
}
if(file_p->drv->ready_cb != NULL) {
if(file_p->drv->ready_cb(file_p->drv) == false) {
file_p->drv = NULL;
return LV_FS_RES_HW_ERR;
}
}
if(file_p->drv->open_cb == NULL) {
file_p->drv = NULL;
return LV_FS_RES_NOT_IMP;
}
const char * real_path = lv_fs_get_real_path(path);
if(file_p->drv->file_size == 0) { /*Is file_d zero size?*/
/*Pass file_d's address to open_cb, so the implementor can allocate memory byself*/
return file_p->drv->open_cb(file_p->drv, &file_p->file_d, real_path, mode);
}
file_p->file_d = lv_mem_alloc(file_p->drv->file_size);
LV_ASSERT_MEM(file_p->file_d);
if(file_p->file_d == NULL) {
file_p->drv = NULL;
return LV_FS_RES_OUT_OF_MEM; /* Out of memory */
}
lv_fs_res_t res = file_p->drv->open_cb(file_p->drv, file_p->file_d, real_path, mode);
if(res != LV_FS_RES_OK) {
lv_mem_free(file_p->file_d);
file_p->file_d = NULL;
file_p->drv = NULL;
}
return res;
}
函数前面是各种检查,申请开文件的必要内存,主要看这一句,参数为设备操作指针,文件指针,真实的目录,操作模式。
open_cb(file_p->drv, &file_p->file_d, real_path, mode);
这个函数的函数指针又指向components\lv_fs_if\lv_fs_fatfs.c中的fs_open函数。lv_fs_if组件即是我们在第一步从LVGL官方下载的文件系统组件,通过lv_conf.h中配置的#define LV_USE_FS_IF 1开关来指向到这里。
要实现对接主要来更改components\lv_fs_if\lv_fs_fatfs.c这个文件里面的每一个文件操作函数。在这个文件中的lv_fs_if_fatfs_init函数中列出了要实现的函数
fs_drv.open_cb = fs_open;
fs_drv.close_cb = fs_close;
fs_drv.read_cb = fs_read;
fs_drv.write_cb = fs_write;
fs_drv.seek_cb = fs_seek;
fs_drv.tell_cb = fs_tell;
fs_drv.free_space_cb = fs_free;
fs_drv.size_cb = fs_size;
fs_drv.remove_cb = fs_remove;
fs_drv.rename_cb = fs_rename;
fs_drv.trunc_cb = fs_trunc;
fs_drv.rddir_size = sizeof(dir_t);
fs_drv.dir_close_cb = fs_dir_close;
fs_drv.dir_open_cb = fs_dir_open;
fs_drv.dir_read_cb = fs_dir_read;
这个.c文件中已经把所有要实现的函数都写了出来,只不过都直接返回
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
第一步先修改初始化函数,这里调用我们第三步初始化底层SD卡驱动的函数,进行底层文件系统的初始化。
/* Initialize your Storage device and File system. */
static void fs_init(void)
{
/* Initialize the SD card and FatFS itself.
* Better to do it in your code to keep this library utouched for easy updating*/
// 初始化 SD 卡和 FatFS 本身。
// 最好在您的代码中执行此操作,以保持此库不变以便于更新
SD_Fatfs_Init();
}
接下来我们把几个文件操作函数全部修改一下。
fs_open
static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode)
{
// 打开文件
(void)file_p;
const char * flags = "";
if(mode == LV_FS_MODE_WR) flags = "wb";
else if(mode == LV_FS_MODE_RD) flags = "rb";
else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD)) flags = "rb+";
sprintf(f_path, "/sdcard/%s", path);
file_t f = fopen(f_path, flags);
if (NULL == f) {
return LV_FS_RES_NOT_EX;
}
fseek(f, 0, SEEK_SET);
/* 'file_p' 是指向文件描述符的指针,我们需要在这里存储我们的文件描述符*/
file_t * fp = file_p;
*fp = f;
return LV_FS_RES_OK;
}
fs_close
static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p)
{
// 关闭文件
(void) drv; /*Unused*/
(void) drv; /*Unused*/
file_t * fp = file_p; // 取出文件操作句柄
if (NULL == fp) {
ESP_LOGE(TAG, "NULL file pointer");
return LV_FS_RES_NOT_EX;
}
if (EOF == fclose(fp)) {
ESP_LOGE(TAG, "Failed close file pointer");
return LV_FS_RES_NOT_EX;
}
return LV_FS_RES_OK;
}
fs_read
static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br)
{
// 读取文件
(void) drv; /*Unused*/
file_t * fp = file_p;// 取出文件操作句柄
*br = fread(buf, 1, btr, (FILE *)file_p);
return LV_FS_RES_OK;
}
fs_write
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
{
// 操作文件写入数据
(void) drv; /*Unused*/
file_t * fp = file_p;// 取出文件操作句柄
*bw = fwrite(buf, 1, btw, (FILE *)file_p);
return LV_FS_RES_OK;
}
fs_seek
static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos, int whence)
{
// 设置文件操作指针偏移
(void) drv; /*Unused*/
fseek((FILE *)file_p, pos, SEEK_SET);
return LV_FS_RES_OK;
}
fs_size
static lv_fs_res_t fs_size(lv_fs_drv_t * drv, void * file_p, uint32_t * size_p)
{
// 获取当前文件大小(Byte)
(void) drv; /*Unused*/
file_t * fp = file_p;// 取出文件操作句柄
uint32_t cur = ftell((FILE *)file_p);
fseek((FILE *)file_p, 0L, SEEK_END);
*size_p = ftell((FILE *)file_p);
fseek((FILE *)file_p, cur, SEEK_SET);// 恢复文件指针
return LV_FS_RES_OK;
}
fs_tell
static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p)
{
// 获取文件当前操作指针位置
(void) drv; /*Unused*/
*pos_p = ftell((FILE *)file_p);
return LV_FS_RES_OK;
}
fs_remove
static lv_fs_res_t fs_remove(lv_fs_drv_t * drv, const char *path)
{
char * pathbuf = lv_mem_alloc(128);
sprintf(pathbuf,"/sdcard/%s",path);
lv_fs_res_t res = LV_FS_RES_UNKNOWN;
if(remove(pathbuf)==0){
lv_mem_free(pathbuf);
return LV_FS_RES_OK;
}else{
lv_mem_free(pathbuf);
return res;
}
}
fs_rename
static lv_fs_res_t fs_rename (lv_fs_drv_t * drv, const char * oldname, const char * newname)
{
(void) drv; /*Unused*/
char * oldnamebuf = lv_mem_alloc(128);
char * newnamebuf = lv_mem_alloc(128);
sprintf(oldnamebuf,"/sdcard/%s",oldname);
sprintf(newnamebuf,"/sdcard/%s",newname);
//
lv_fs_res_t res = LV_FS_RES_UNKNOWN;
if(rename(oldnamebuf,newnamebuf)==0){
lv_mem_free(oldnamebuf);
lv_mem_free(newnamebuf);
return LV_FS_RES_OK;
}else{
lv_mem_free(oldnamebuf);
lv_mem_free(newnamebuf);
return res;
}
}
fs_free
static lv_fs_res_t fs_free(lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p)
{
lv_fs_res_t res = LV_FS_RES_NOT_IMP;
size_t total_sectors = 0,free_sectors = 0;
size_t sd_total = 0,sd_total_KB = 0,sd_total_MB = 0;
size_t sd_free = 0,sd_free_KB = 0,sd_free_MB = 0;
FATFS *fs;
size_t free_clusters;
FRESULT fres = f_getfree("0:", &free_clusters, &fs);
if(fres == FR_OK){
total_sectors = (fs->n_fatent - 2) * fs->csize;
free_sectors = free_clusters * fs->csize;
sd_total = total_sectors/1024;
sd_total_KB = sd_total*fs->ssize;
sd_total_MB = (sd_total*fs->ssize)/1024;
sd_free = free_sectors/1024;
sd_free_KB = sd_free*fs->ssize;
sd_free_MB = (sd_free*fs->ssize)/1024;
if (total_p != NULL) {
*total_p = sd_total_KB;
}
if (free_p != NULL) {
*free_p = sd_free_KB;
}
return LV_FS_RES_OK;
}else{
*total_p = sd_total_KB;
*free_p = sd_free_KB;
return LV_FS_RES_UNKNOWN;
}
//printf("SD Cart sd_total_KB %d KByte\r\n ", sd_total_KB);
// printf("SD Cart sd_total_MB %d MByte\r\n ", sd_total_MB);
// printf("SD Cart sd_free_KB %d KByte\r\n ", sd_free_KB);
// printf("SD Cart sd_free_MB %d MByte\r\n ", sd_free_MB);
// 假设总大小小于4GiB,对于SPI Flash应该为true
}
fs_dir_open
static lv_fs_res_t fs_dir_open (lv_fs_drv_t * drv, void * dir_p, const char *path)
{
dir_t file_dir = NULL;
//file_dir = opendir("/sdcard/");
(void)dir_p;
(void) drv; /*Unused*/
char * pathbuf = lv_mem_alloc(128);
sprintf(pathbuf,"/sdcard/%s",path);
printf("fs_dir_open %s\r\n",pathbuf);
file_dir = opendir(pathbuf);
if (NULL == file_dir) {
lv_mem_free(pathbuf);
return LV_FS_RES_FS_ERR;
}
lv_mem_free(pathbuf);
/* 'file_p' 是指向文件描述符的指针,我们需要在这里存储我们的文件描述符*/
dir_t * fd = dir_p;
*fd = file_dir;
return LV_FS_RES_OK;
}
fs_dir_read
static lv_fs_res_t fs_dir_read (lv_fs_drv_t * drv, void * dir_p, char *fn)
{
struct dirent *entry;
dir_t *mdir_p = dir_p;
do {
entry = readdir(*mdir_p);
if(entry) {
if(entry->d_type == DT_DIR) sprintf(fn, "/%s", entry->d_name);
else strcpy(fn, entry->d_name);
} else {
strcpy(fn, "");
}
} while(strcmp(fn, "/.") == 0 || strcmp(fn, "/..") == 0);
return LV_FS_RES_OK;
}
fs_dir_close
static lv_fs_res_t fs_dir_close (lv_fs_drv_t * drv, void * dir_p)
{
(void) drv; /*Unused*/
closedir(dir_p);
return LV_FS_RES_OK;
}
五、测试代码
接下来就是用lvgl提示的函数来实际操作一下文件,测试一下,在这之前,要先在主函数中初始化LVGL文件系统,在lv_init函数之后调用lv_fs_if_init();初始化文件系统,并定义一些一会用到的东西,例文件操作句柄,文件夹操作句柄,返回值,数量变量,读取内容数组等
lv_init(); // 初始化LittlevGL
lvgl_driver_init(); // 初始化液晶SPI驱动 触摸芯片SPI/IIC驱动
lv_fs_if_init();
lv_fs_file_t f;
lv_fs_dir_t d;
lv_fs_res_t res;
uint32_t resCount;
uint8_t buf[64];
编写操作函数
具体操作说明如下:
用只读方式打开S:/hello.txt文件,测试文件是否存在
用写入方式打开S:/hello.txt文件,并写入hellobug esp32字符串,然后关闭文件
用只读方式打开S:/hello.txt文件,并读取内容并打印,然后关闭文件
删除S:/bug.txt(第一次运行时,肯定不存在)
将hello.txt重命名为bug.txt
只读方式打开bug.txt,获取一下文件大小
读取bug.txt所有内容并打印
操作文件指针移到第7字节
获取文件当前指针位置
从指针当前位置读取文件内容并打印
关闭文件
打开根目录
循环读取目录下所有目录及文件
关闭目录
然后添加如下测试代码。基本上用到了刚才改写的所有接口。
// 用只读方式打开一个文件,来判断文件是否存在
res = lv_fs_open(&f,"S:/hello.txt", LV_FS_MODE_RD);
if (res == LV_FS_RES_OK) { // 文件存在
lv_fs_close(&f); // 关闭文件
ESP_LOGI(TAG,"'hello.txt' file is existsres : %d",res);
}else if(res == LV_FS_RES_NOT_EX){// 文件不存在
ESP_LOGI(TAG,"'hello.txt' file is not exists res : %d",res);
}
/创建一个文件并写入内容
res = lv_fs_open(&f,"S:/hello.txt", LV_FS_MODE_WR);// 创建一个文件
if (res == LV_FS_RES_OK) {
ESP_LOGI(TAG,"Create file 'hello.txt' Success res : %d",res);
res = lv_fs_write(&f,"hellobug esp32", sizeof("hellobug esp32"), &resCount);// 创建一个文件
if (res == LV_FS_RES_OK) {
ESP_LOGI(TAG,"Write file 'hello.txt' Success res : %d WriteByte: %d",res,resCount);
}
}
lv_fs_close(&f);
/读取刚才创建的文件并打印内容
res = lv_fs_open(&f,"S:/hello.txt", LV_FS_MODE_RD);// 只读方式打开一个文件
if(res == LV_FS_RES_OK) {
ESP_LOGI(TAG,"lv_fs_open->Success %d",res);
memset(buf,0,64);
res = lv_fs_read(&f, buf, 64, &resCount);
if(res != LV_FS_RES_OK) {
ESP_LOGI(TAG,"lv_fs_read->Failed %d",res);
}else{
ESP_LOGI(TAG,"lv_fs_read->Success %d",res);
}
ESP_LOGI(TAG,"lv_fs_read ReadByte : %d Content : %s",resCount,buf);
lv_fs_close(&f);
}else{
ESP_LOGI(TAG,"lv_fs_open->Failed %d",res);
}
// 删除文件
res = lv_fs_remove("S:/bug.txt");
ESP_LOGI(TAG,"lv_fs_remove-> bug.txt res:%d",res);
// 重命名文件
res = lv_fs_rename("S:/hello.txt","S:/bug.txt");
ESP_LOGI(TAG,"lv_fs_rename-> oldname:hello.txt newname:bug.txt res:%d",res);
/读取刚才改名的文件并打印内容
res = lv_fs_open(&f,"S:/bug.txt", LV_FS_MODE_RD);// 只读方式打开一个文件
if(res == LV_FS_RES_OK) {
// 获取文件大小
res = lv_fs_size(&f,&resCount);
ESP_LOGI(TAG,"lv_fs_size-> bug.txt file size : %d Byte",resCount);
ESP_LOGI(TAG,"lv_fs_open-> S:/bug.txt Success %d",res);
memset(buf,0,64);
res = lv_fs_read(&f, buf, 64, &resCount);
if(res != LV_FS_RES_OK) {
ESP_LOGI(TAG,"lv_fs_read-> S:/bug.txt Failed %d",res);
}else{
ESP_LOGI(TAG,"lv_fs_read-> S:/bug.txt Success %d",res);
}
ESP_LOGI(TAG,"lv_fs_read S:/bug.txt ReadByte : %d Content : %s",resCount,buf);
// 定位文件操作指针示例
res = lv_fs_seek(&f, 7);
ESP_LOGI(TAG,"lv_fs_seek-> S:/bug.txt res %d",res);
// 获取文件操作指针示例
res = lv_fs_tell(&f, &resCount);
ESP_LOGI(TAG,"lv_fs_tell-> S:/bug.txt res %d index: %d",res,resCount);
memset(buf,0,64);
res = lv_fs_read(&f, buf, 64, &resCount);
ESP_LOGI(TAG,"lv_fs_read seek 7Byte S:/bug.txt ReadByte : %d Content : %s",resCount,buf);
lv_fs_close(&f);
}else{
ESP_LOGI(TAG,"lv_fs_open-> S:/bug.txt Failed %d",res);
}
res = lv_fs_dir_open(&d,"S:/");
ESP_LOGI(TAG,"lv_fs_dir_open-> res %d",res);
while(1){
memset(buf,0,64);
res = lv_fs_dir_read(&d,(char *)buf);
if(buf[0] == '\0'){
break;
}
ESP_LOGI(TAG,"lv_fs_dir_read res : %d Content : %s",res,buf);
}
res = lv_fs_dir_close(&d);
ESP_LOGI(TAG,"lv_fs_dir_close res : %d ",res);
测试结果打印:
版权声明:本文为CSDN博主「路过人间本尊」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/cnicfhnui/article/details/118972851
暂无评论