class="hide-preCode-box">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
结果验证
编译运行得到的结果为:
entry cpup test example
the current system cpu usage is: 8.2
the history system cpu usage in all time:8.9
cpu usage of the cpupTestTask:
TaskID: 5
usage: 0.5
cpu usage of the cpupTestTask in all time:
TaskID: 5
usage: 0.5
exit cpup test example
根据实际运行环境,上文中的数据会有差异,非固定结果
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
动态加载
基本概念
在硬件资源有限的小设备中,需要通过算法的动态部署能力来解决无法同时部署多种算法的问题。以开发者易用为主要考虑因素,同时考虑到多平台的通用性,LiteOS-M选择业界标准的ELF加载方案,方便拓展算法生态。LiteOS-M提供类似于dlopen、dlsym等接口,APP通过动态加载模块提供的接口可以加载、卸载相应算法库。如图1所示,APP需要通过三方算法库所需接口获取对应信息输出,三方算法库又依赖内核提供的基本接口,如malloc等。APP加载所需接口,并对相关的未定义符号完成重定位后,APP即可调用该接口完成功能调用。目前动态加载组件只支持arm架构。此外,待加载的共享库需要验签或者限制来源,确保系统的安全性。
图1 LiteOS-M内核动态加载架构图
运行机制
符号表导出
共享库调用内核接口需要内核主动暴露动态库所需的接口,如图2所示,该机制将符号信息编译到指定段中,调用SYM_EXPORT宏即可完成对指定符号的信息导出。符号信息通过结构体SymInfo描述,成员包括符号名和符号地址信息,宏SYM_EXPORT通过__attribute__编译属性将符号信息导入.sym.*段中。
typedef struct {
CHAR *name;
UINTPTR addr;
} SymInfo;
#define SYM_EXPORT(func) \
const SymInfo sym_##func __attribute__((section(".sym."#func))) = { \
.name = #func, \
.addr = (UINTPTR)func \
};
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
图2 导出的符号表信息
ELF文件加载
加载过程中,根据ELF文件的句柄以及程序头表的段偏移可以得到需要加载到内存的LOAD段,一般有两个段,只读段及读写段,如下所示,可以用readelf -l查看ELF文件的LOAD段信息。如图3所示,根据相应的对齐属性申请物理内存,通过每个段的加载基址及偏移将代码段或数据段写入内存中。
$ readelf -l lib.so
Elf file type is DYN (Shared object file)
Entry point 0x5b4
There are 4 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
EXIDX 0x000760 0x00000760 0x00000760 0x00008 0x00008 R 0x4
LOAD 0x000000 0x00000000 0x00000000 0x0076c 0x0076c R E 0x10000LOAD 0x00076c 0x0001076c 0x0001076c 0x0010c 0x00128 RW 0x10000
DYNAMIC 0x000774 0x00010774 0x00010774 0x000c8 0x000c8 RW 0x4
Section to Segment mapping:
Segment Sections...
00 .ARM.exidx
01 .hash .dynsym .dynstr .rel.dyn .rel.plt .init .plt .text .fini .ARM.exidx .eh_frame
02 .init_array .fini_array .dynamic .got .data .bss
03 .dynamic
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
图3 ELF文件的加载过程
ELF文件链接
如图4所示,通过ELF文件的.dynamic段获取重定位表,遍历表中每一个需要重定位的条目,再根据需要重定位的符号名在共享库和内核提供的导出符号表中查找相应符号并更新相应的重定位信息。
图4 ELF文件的链接过程
ELF支持规格
ELF支持类型
编译共享库时,添加-fPIC可以编译出位置无关代码(-fPIC为编译选项),此时共享库文件类型为ET_DYN,其可以加载至任意有效的地址区间。
例:arm-none-eabi-gcc -fPIC –shared –o lib.so lib.c
ELF共享库编译链接选项
“-nostdlib”编译链接选项:不依赖编译器中lib库。
“-nostartfiles”编译链接选项:不依赖编译器中启动相关的文件。
“-fPIC”编译选项:可编译位置无关的共享库。
“-z max-page-size=4”链接选项:二进制文件中可加载段的对齐字节数为4,可节约内存,可用于动态库。
“-mcpu=”需要指定对应的CPU架构。
约束
不支持应用程序加载,只支持共享库加载。 待加载的共享库不能依赖编译器中的libc库及其他共享库,只能依赖内核提供的对外接口(由导出的符号表提供)。 依赖交叉编译器及文件系统。
文件系统
VFS
基本概念
VFS(Virtual File System) 是文件系统的虚拟层,它不是一个实际的文件系统,而是一个异构文件系统之上的软件粘合层,为用户提供统一的类Unix文件操作接口。由于不同类型的文件系统接口不统一,若系统中有多个文件系统类型,访问不同的文件系统就需要使用不同的非标准接口。而通过在系统中添加VFS层,提供统一的抽象接口,屏蔽了底层异构类型的文件系统的差异,使得访问文件系统的系统调用不用关心底层的存储介质和文件系统类型,提高开发效率。
M核的文件系统子系统当前支持的文件系统有FATFS与LittleFS 。通过VFS层提供了POSIX标准的操作,保持了接口的一致性,但是因为M核的资源非常紧张,VFS层非常轻薄,没有提供类似A核的高级功能(如pagecache等),主要是接口的标准化和适配工作,具体的事务由各个文件系统实际承载。M核文件系统支持的功能如下表所示:
接口说明
表1 文件操作
class="table-box">接口名 描述 FATFS LITTLEFS open 打开文件 支持 支持 close 关闭文件 支持 支持 read 读取文件内容 支持 支持 write 往文件写入内容 支持 支持 lseek 设置文件偏移位置 支持 支持 stat 通过文件路径名获取文件信息 支持 支持 unlink 删除文件 支持 支持 rename 重命名文件 支持 支持 fstat 通过文件句柄获取文件信息 支持 支持 fsync 文件内容刷入存储设备 支持 支持
表2 目录操作
class="table-box">接口名 描述 FATFS LITTLEFS mkdir 创建目录 支持 支持 opendir 打开目录 支持 支持 readdir 读取目录项内容 支持 支持 closedir 关闭目录 支持 支持 rmdir 删除目录 支持 支持
表3 分区操作
class="table-box">接口名 描述 FATFS LITTLEFS mount 分区挂载 支持 支持 umount 分区卸载 支持 支持 umount2 分区卸载,可通过MNT_FORCE参数进行强制卸载 支持 不支持 statfs 获取分区信息 支持 不支持
ioctl,fcntl等接口由不同的lib库支持,与底层文件系统无关。
FAT
基本概念
FAT文件系统是File Allocation Table(文件配置表)的简称,主要包括DBR区、FAT区、DATA区三个区域。其中,FAT区各个表项记录存储设备中对应簇的信息,包括簇是否被使用、文件下一个簇的编号、是否文件结尾等。FAT文件系统有FAT12、FAT16、FAT32等多种格式,其中,12、16、32表示对应格式中FAT表项的比特数。FAT文件系统支持多种介质,特别在可移动存储介质(U盘、SD卡、移动硬盘等)上广泛使用,使嵌入式设备和Windows 、Linux等桌面系统保持很好的兼容性,方便用户管理操作文件。
OpenHarmony内核支持FAT12、FAT16与FAT32三种格式的FAT文件系统,具有代码量小、资源占用小、可裁切、支持多种物理介质等特性,并且与Windows、Linux等系统保持兼容,支持多设备、多分区识别等功能。OpenHarmony内核支持硬盘多分区,可以在主分区以及逻辑分区上创建FAT文件系统。
开发指导
驱动适配
FAT文件系统的使用需要底层MMC相关驱动的支持。在一个带MMC存储设备的板子上运行FATFS,需要:
1、适配板端EMMC驱动,实现disk_status、disk_initialize、disk_read、disk_write、disk_ioctl接口;
2、新增fs_config.h文件,配置FS_MAX_SS(存储设备最大sector大小)、FF_VOLUME_STRS(分区名)等信息,例如:
#define FF_VOLUME_STRS "system", "inner", "update", "user"
#define FS_MAX_SS 512
#define FAT_MAX_OPEN_FILES 50
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
分区挂载
移植FATFS到新硬件设备上,需要在初始化flash驱动后,完成设备分区。
设备分区接口:int LOS_DiskPartition(const char *dev, const char *fsType, int *lengthArray, int *addrArray, int partNum);
dev:设备名称, 如“spinorblk0” fsType:文件系统类型,”vfat“ lengthArray:该设备上各分区的长度列表,fatfs填入百分比即可 addrArray:该设备上各分区的起始地址列表 partNum:分区的个数
格式化接口:int LOS_PartitionFormat(const char *partName, char *fsType, void *data);
partName:分区名称,设备名称+ ‘p’ + 分区号,如“spinorblk0p0” fsType:文件系统类型,”vfat“ data:私有数据 传入(VOID *)formatType,(如FMT_FAT, FMT_FAT32)
mount接口:int mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data);
source:分区名称,设备名称+ ‘p’ + 分区号,如“spinorblk0p0” target:挂载路径 filesystemtype:文件系统类型,”vfat“ mountflags:mount配置参数 data:私有数据,传入(VOID *)formatType,(如FMT_FAT, FMT_FAT32)
本参考代码已在 ./device/qemu/arm_mps2_an386/liteos_m/board/fs/fs_init.c 中实现,M核qemu上可直接使用,请参考并根据实际硬件修改。
#include "fatfs_conf.h"
#include "fs_config.h"
#include "los_config.h"
#include "ram_virt_flash.h"
#include "los_fs.h"
struct fs_cfg {
CHAR *mount_point;
struct PartitionCfg partCfg;
};
INT32 FatfsLowLevelInit()
{
INT32 ret;
INT32 i;
UINT32 addr;
int data = FMT_FAT32;
const char * const pathName[FF_VOLUMES] = {FF_VOLUME_STRS};
HalLogicPartition *halPartitionsInfo = getPartitionInfo(); /* 获取长度和起始地址的函数,请根据实际单板适配 */
INT32 lengthArray[FF_VOLUMES] = {25, 25, 25, 25};
INT32 addrArray[FF_VOLUMES];
/* 配置各分区的地址和长度,请根据实际单板适配 */
for (i = 0; i < FF_VOLUMES; i++) {
addr = halPartitionsInfo[FLASH_PARTITION_DATA1].partitionStartAddr + i * 0x10000;
addrArray[i] = addr;
FlashInfoInit(i, addr);
}
/* 配置分区信息,请根据实际单板适配 */
SetupDefaultVolToPartTable();
ret = LOS_DiskPartition("spinorblk0", "vfat", lengthArray, addrArray, FF_VOLUMES);
printf("%s: DiskPartition %s\n", __func__, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
ret = LOS_PartitionFormat("spinorblk0p0", "vfat", &data);
printf("%s: PartitionFormat %s\n", __func__, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
ret = mount("spinorblk0p0", "/system", "vfat", 0, &data);
printf("%s: mount fs on '%s' %s\n", __func__, pathName[0], (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
return 0;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
开发流程
说明:
FATFS文件与目录操作:
单个文件大小不超过4G。 支持同时打开的文件数最大为FAT_MAX_OPEN_FILES,文件夹数最大为FAT_MAX_OPEN_DIRS。 暂不支持根目录管理,文件/目录名均以分区名开头,例如“user/testfile”就是在“user”分区下名为“testfile”的文件或目录。 若需要同时多次打开同一文件,必须全部使用只读方式(O_RDONLY)。以可写方式(O_RDWR、O_WRONLY等)只能打开一次。 读写指针未分离,例如以O_APPEND(追加写)方式打开文件后,读指针也在文件尾,从头读文件前需要用户手动置位。 暂不支持文件与目录的权限管理。 stat及fstat接口暂不支持查询修改时间、创建时间和最后访问时间。微软FAT协议不支持1980年以前的时间。 FATFS分区挂载与卸载:
支持以只读属性挂载分区。当mount函数的入参为MS_RDONLY时,所有的带有写入的接口,如write、mkdir、unlink,以及非O_RDONLY属性的open,将均被拒绝。 mount支持通过MS_REMOUNT标记修改已挂载分区的权限。 在umount操作前,需确保所有目录及文件全部关闭。 umount2支持通过MNT_FORCE参数强制关闭所有文件与文件夹并umount,但可能造成数据丢失,请谨慎使用。 FATFS支持重新划分存储设备分区、格式化分区,对应接口为fatfs_fdisk与fatfs_format:
在fatfs_format操作之前,若需要格式化的分区已挂载,需确保分区中的所有目录及文件全部关闭,并且分区umount。 在fatfs_fdisk操作前,需要该设备中的所有分区均已umount。 fatfs_fdisk与fatfs_format会造成设备数据丢失,请谨慎使用。
编程实例
实例描述
本实例实现以下功能:
创建目录“system/test”
在“system/test”目录下创建文件“file.txt”
在文件起始位置写入“Hello OpenHarmony!”
将文件内容刷入设备中
设置偏移到文件起始位置
读取文件内容
关闭文件
删除文件
删除目录
示例代码
前提条件:
系统已将设备分区挂载到目录,qemu默认已挂载system。
在kernel/liteos_m目录下执行 make menuconfig 命令配置"FileSystem->Enable FS VFS"开启FS功能;
开启FS后出现新选项“Enable FAT”开启FAT。
代码实现如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数ExampleFatfs。
#include
#include
#include "sys/stat.h"
#include "fcntl.h"
#include "unistd.h"
#define BUF_SIZE 20
#define TEST_ROOT "system" /* 测试的根目录请根据实际情况调整 */
VOID ExampleFatfs(VOID)
{
int ret;
int fd;
ssize_t len;
off_t off;
char dirName[BUF_SIZE] = TEST_ROOT"/test";
char fileName[BUF_SIZE] = TEST_ROOT"/test/file.txt";
char writeBuf[BUF_SIZE] = "Hello OpenHarmony!";
char readBuf[BUF_SIZE] = {0};
/* 创建测试目录 */
ret = mkdir(dirName, 0777);
if (ret != LOS_OK) {
printf("mkdir failed.\n");
return;
}
/* 创建可读写测试文件 */
fd = open(fileName, O_RDWR | O_CREAT, 0777);
if (fd < 0) {
printf("open file failed.\n");
return;
}
/* 将writeBuf中的内容写入文件 */
len = write(fd, writeBuf, strlen(writeBuf));
if (len != strlen(writeBuf)) {
printf("write file failed.\n");
return;
}
/* 将文件内容刷入存储设备中 */
ret = fsync(fd);
if (ret != LOS_OK) {
printf("fsync failed.\n");
return;
}
/* 将读写指针偏移至文件头 */
off = lseek(fd, 0, SEEK_SET);
if (off != 0) {
printf("lseek failed.\n");
return;
}
/* 将文件内容读出至readBuf中,读取长度为readBuf大小 */
len = read(fd, readBuf, sizeof(readBuf));
if (len != strlen(writeBuf)) {
printf("read file failed.\n");
return;
}
printf("%s\n", readBuf);
/* 关闭测试文件 */
ret = close(fd);
if (ret != LOS_OK) {
printf("close failed.\n");
return;
}
/* 删除测试文件 */
ret = unlink(fileName);
if (ret != LOS_OK) {
printf("unlink failed.\n");
return;
}
/* 删除测试目录 */
ret = rmdir(dirName);
if (ret != LOS_OK) {
printf("rmdir failed.\n");
return;
}
return;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
结果验证
编译运行得到的结果为:
Hello OpenHarmony!
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
LittleFS
基本概念
LittleFS是一个小型的Flash文件系统,它结合日志结构(log-structured)文件系统和COW(copy-on-write)文件系统的思想,以日志结构存储元数据,以COW结构存储数据。这种特殊的存储方式,使LittleFS具有强大的掉电恢复能力(power-loss resilience)。分配COW数据块时LittleFS采用了名为统计损耗均衡的动态损耗均衡算法,使Flash设备的寿命得到有效保障。同时LittleFS针对资源紧缺的小型设备进行设计,具有极其有限的ROM和RAM占用,并且所有RAM的使用都通过一个可配置的固定大小缓冲区进行分配,不会随文件系统的扩大占据更多的系统资源。
当在一个资源非常紧缺的小型设备上,寻找一个具有掉电恢复能力并支持损耗均衡的Flash文件系统时,LittleFS是一个比较好的选择。
开发指导
移植LittleFS到新硬件设备上,需要在初始化flash驱动后,完成设备分区。
设备分区接口:int LOS_DiskPartition(const char *dev, const char *fsType, int *lengthArray, int *addrArray, int partNum);
dev:设备名称 fsType:文件系统类型, “littlefs” lengthArray:该设备上各分区的长度列表 addrArray:该设备上各分区的起始地址列表 partNum:分区的个数
格式化接口:int LOS_PartitionFormat(const char *partName, char *fsType, void *data);
partName:分区名称 fsType:文件系统类型, “littlefs” data:私有数据 传入(VOID *)struct fs_cfg
mount接口:int mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data);
source:分区名称 target:挂载路径 filesystemtype:文件系统类型,“littlefs” mountflags:mount配置参数 data:私有数据,传入(VOID *)struct fs_cfg
本参考代码已在 ./device/qemu/arm_mps2_an386/liteos_m/board/fs/fs_init.c 中实现,M核qemu上可直接使用,请参考并根据实际硬件修改。
#include "los_config.h"
#include "ram_virt_flash.h"
#include "los_fs.h"
struct fs_cfg {
CHAR *mount_point;
struct PartitionCfg partCfg;
};
INT32 LfsLowLevelInit()
{
INT32 ret;
struct fs_cfg fs[LOSCFG_LFS_MAX_MOUNT_SIZE] = {0};
HalLogicPartition *halPartitionsInfo = getPartitionInfo(); /* 获取长度和起始地址的函数,请根据实际单板适配 */
INT32 lengthArray[2];
lengthArray[0]= halPartitionsInfo[FLASH_PARTITION_DATA0].partitionLength;
INT32 addrArray[2];
addrArray[0] = halPartitionsInfo[FLASH_PARTITION_DATA0].partitionStartAddr;
ret = LOS_DiskPartition("flash0", "littlefs", lengthArray, addrArray, 2);
printf("%s: DiskPartition %s\n", __func__, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
fs[0].mount_point = "/littlefs";
fs[0].partCfg.partNo = 0;
fs[0].partCfg.blockSize = 4096; /* 4096, lfs block size */
fs[0].partCfg.blockCount = 1024; /* 2048, lfs block count */
fs[0].partCfg.readFunc = virt_flash_read; /* flash读函数,请根据实际单板适配 */
fs[0].partCfg.writeFunc = virt_flash_write; /* flash写函数,请根据实际单板适配 */
fs[0].partCfg.eraseFunc = virt_flash_erase; /* flash擦函数,请根据实际单板适配 */
fs[0].partCfg.readSize = 256; /* 256, lfs read size */
fs[0].partCfg.writeSize = 256; /* 256, lfs prog size */
fs[0].partCfg.cacheSize = 256; /* 256, lfs cache size */
fs[0].partCfg.lookaheadSize = 16; /* 16, lfs lookahead size */
fs[0].partCfg.blockCycles = 1000; /* 1000, lfs block cycles */
ret = LOS_PartitionFormat("flash0", "littlefs", &fs[0].partCfg);
printf("%s: PartitionFormat %s\n", __func__, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
ret = mount(NULL, fs[0].mount_point, "littlefs", 0, &fs[0].partCfg);
printf("%s: mount fs on '%s' %s\n", __func__, fs[0].mount_point, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
return 0;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
其中.readFunc,.writeFunc,.eraseFunc分别对应该硬件平台上的底层的读写\擦除等接口。
readSize 每次读取的字节数,可以比物理读单元大以改善性能,这个数值决定了读缓存的大小,但值太大会带来更多的内存消耗。
writeSize 每次写入的字节数,可以比物理写单元大以改善性能,这个数值决定了写缓存的大小,必须是readSize的整数倍,但值太大会带来更多的内存消耗。
blockSize 每个擦除块的字节数,可以比物理擦除单元大,但此数值应尽可能小因为每个文件至少会占用一个块。必须是writeSize的整数倍。
blockCount 可以被擦除的块数量,这取决于块设备的容量及擦除块的大小。
示例代码
前提条件:
系统已将设备分区挂载到目录,qemu默认已挂载/littlefs。
在kernel/liteos_m目录下执行 make menuconfig 命令配置"FileSystem->Enable FS VFS"开启FS功能;
开启FS后出现新选项“Enable Little FS”开启littlefs。
代码实现如下:
本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数ExampleLittlefs。
#include
#include
#include "sys/stat.h"
#include "fcntl.h"
#include "unistd.h"
#define BUF_SIZE 20
#define TEST_ROOT "/littlefs" /* 测试的根目录请根据实际情况调整 */
VOID ExampleLittlefs(VOID)
{
int ret;
int fd;
ssize_t len;
off_t off;
char dirName[BUF_SIZE] = TEST_ROOT"/test";
char fileName[BUF_SIZE] = TEST_ROOT"/test/file.txt";
char writeBuf[BUF_SIZE] = "Hello OpenHarmony!";
char readBuf[BUF_SIZE] = {0};
/* 创建测试目录 */
ret = mkdir(dirName, 0777);
if (ret != LOS_OK) {
printf("mkdir failed.\n");
return;
}
/* 创建可读写测试文件 */
fd = open(fileName, O_RDWR | O_CREAT, 0777);
if (fd < 0) {
printf("open file failed.\n");
return;
}
/* 将writeBuf中的内容写入文件 */
len = write(fd, writeBuf, strlen(writeBuf));
if (len != strlen(writeBuf)) {
printf("write file failed.\n");
return;
}
/* 将文件内容刷入存储设备中 */
ret = fsync(fd);
if (ret != LOS_OK) {
printf("fsync failed.\n");
return;
}
/* 将读写指针偏移至文件头 */
off = lseek(fd, 0, SEEK_SET);
if (off != 0) {
printf("lseek failed.\n");
return;
}
/* 将文件内容读出至readBuf中,读取长度为readBuf大小 */
len = read(fd, readBuf, sizeof(readBuf));
if (len != strlen(writeBuf)) {
printf("read file failed.\n");
return;
}
printf("%s\n", readBuf);
/* 关闭测试文件 */
ret = close(fd);
if (ret != LOS_OK) {
printf("close failed.\n");
return;
}
/* 删除测试文件 */
ret = unlink(fileName);
if (ret != LOS_OK) {
printf("unlink failed.\n");
return;
}
/* 删除测试目录 */
ret = rmdir(dirName);
if (ret != LOS_OK) {
printf("rmdir failed.\n");
return;
}
return LOS_OK;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
结果验证
首次编译运行得到的结果为:
Hello OpenHarmony!
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
如果大家想更加深入的学习 OpenHarmony(鸿蒙南向) 开发的全栈内容,不妨可以参考以下相关学习文档进行学习,助你快速提升自己:
搭建开发环境 Windows 开发环境的搭建 Ubuntu 开发环境搭建 Linux 与 Windows 之间的文件共享 ……
构建子系统 启动流程 子系统 分布式任务调度子系统 分布式通信子系统 驱动子系统 ……
写在最后
如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙: 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:https://qr21.cn/FV7h05
data-report-view="{"mod":"1585297308_001","spm":"1001.2101.3001.6548","dest":"https://blog.csdn.net/maniuT/article/details/140895371","extend1":"pc","ab":"new"}">>
id="blogExtensionBox" style="width:400px;margin:auto;margin-top:12px" class="blog-extension-box"> class="blog_extension blog_extension_type2" id="blog_extension">
class="extension_official" data-report-click="{"spm":"1001.2101.3001.6471"}" data-report-view="{"spm":"1001.2101.3001.6471"}">
class="blog_extension_card_left">
class="blog_extension_card_cont">
鸿蒙开发学习资料领取!!!
class="blog_extension_card_cont_r">
微信名片
评论记录:
回复评论: