文件系统
简介
文件系统是一套实现了数据的存储、分级组织、访问和获取等操作的抽象数据类型,是一种用于向用户提供底层数据访问的机制。文件系统存储的基本单位是文件,即数据是按照一个个文件的方式进行组织。当文件比较多时,将导致文件繁多,不易分类、重名的问题。而文件夹作为一个容纳多个文件的容器而存在。
在本操作系统中,为了能够支持多种文件系统,实现了虚拟文件系统。对上而言,可以提供统一的POSIX接口,方便用户使用。对下而言,可以注册不同的具体文件系统类型。整个文件系统的层次架构如下:
POSIX接口层
POSIX表示可移植操作系统接口(Portable OperaTIng System Interface of UNIX,缩写为 POSIX ),POSIX标准定义了操作系统应该为应用程序提供的接口标准,是IEEE为要在各种UNIX操作系统上运行的软件而定义的一系列API标准的总称,其正式称呼为IEEE 1003。POSIX标准意在期望获得源代码级别的软件可移植性。换句话说,为一个POSIX兼容的操作系统编写的程序,应该可以在任何其它的POSIX操作系统(即使是来自另一个厂商)上编译执行。
本操作系统支持POSIX标准接口,因此可以很方便的将 Linux/Unix 的程序移植到本操作系统上。
虚拟文件系统
本操作系统支持多种文件系统,如FATFS、CUTEFS、NFS、YAFFS2等。不同的文件系统有各自不同的管理文件的方式,对于用户而言,最好不用去关心每种文件系统的文件存取方式。因此本操作系统在POSIX接口层和具体文件系统之间引入了一个抽象层,这个抽象层称之为虚拟文件系统(Virtual File System)。
为了能够支持多种实际文件系统,VFS定义了各种文件系统都支持的基本的、概念上的接口和数据结构,VFS不用关心具体文件系统的实现细节。
具体文件系统
本操作系统目前支持以下文件系统,方便用户根据实际情况选用:
FATFS:本组件支持的FAT文件系统是移植的一个兼容微软FAT格式的通用FAT文件系统模块(presented by ChaN),非常适合小型嵌入式设备开发。
CUTEFS:一种小巧的文件系统,支持各种文件及目录操作,目前需要配合RAMDISK使用。
DEVFS:设备文件系统,可以将系统中的设备在/dev文件夹下虚拟成文件。
NFS:网络文件系统,本系统移植了一个网络文件系统客户端,可以通过操作本地文件系统一样的方式去访问服务器端的文件。
JFFS2:JFFS(Journalling Flash FileSystem)文件系统最早是由瑞典Axis Communications AB在嵌入式系统上开发的Flash文件系统,而JFFS2是RedHat公司在JFFS的基础上开发的文件系统。这是一种日志型文件系统,主要用于Nor Flash,支持数据压缩功能,支持磨损均衡可延长FLASH使用寿命,支持垃圾回收机制。
YAFFS2:YAFFS(Yet Another Flash File System)文件系统是一种针对Nand Flash特性而设计的嵌入式文件系统。目前有两个版本,Yaffs1支持page大小512byte的Nand Flash,Yaffs2支持更大page(2kbyte)的Nand Flash。这也是一种日志型文件系统,主要用于Nand Flash,支持磨损均衡,支持垃圾回收。
Littlefs:Littlefs是适用MCU等级嵌入式应用场景设计的小型Flash文件系统,特别针对资源受限场景设计,效率高,资源占用小,掉电可恢复,均衡Flash块写入磨损。
设备抽象层
设备抽象层将物理设备,如SD Card、Flash等抽象成文件系统能够访问的设备,例如FAT文件系统要求存储设备是块设备类型。不同的文件系统一般是独立于存储设备驱动而实现的,因此需要把底层存储设备驱动接口与具体文件系统对接起来,文件系统才能正常使用。
初始化和挂载文件系统
文件系统要能够正常使用,一般需要先经过以下几个步骤:
初始化VFS组件
注册具体的文件系统
在存储器上创建块设备
在块设备上格式化文件系统
挂载设备到某个路径
文件系统不再使用时,可以卸载
初始化VFS组件
VFS组件的的初始化是由函数vfs_init()完成。vfs_init() 函数会初始化 VFS 所需的相关资源,创建一些关键的数据结构(包括文件系统操作表,文件系统表,文件描述符表等)。有了这些数据结构,VFS便能在系统中记录和访问特定的文件系统,并获得对文件的操作方法。本操作系统中有自动初始化功能,该函数将会被自动调用。
注册文件系统
用户根据自己的需要选择具体的文件系统并注册到VFS中,通过函数vfs_register()实现,它会将具体文件系统的操作接口与VFS中的文件系统操作表关联起来。本操作系统中在配置时如果打开了某种文件系统,那么在初始化阶段将会调用该函数注册该文件系统。
将存储设备注册为块设备
存储设备初始化后,需要将该存储设备注册为块设备,通过函数os_device_register()实现,它会将设备的操作接口与设备名关联起来。以后需要设备时,可以使用os_device_find()通过设备名找到实际设备,进而可以获取到实际设备的操作接口。
格式化文件系统
不同具体文件系统的组织方式是不一样的,所以在使用具体文件系统之前,需要将块设备按照某种文件系统进行格式化,通过函数vfs_mkfs()实现。它会在设备的某个区域上,写入一些符合具体文件系统格式的数据,表明该文件系统的一些特征。后续在访问该设备时,就能识别到该设备上的数据是否是按照该文件系统组织的,才能根据该文件系统的操作接口去访问文件。
挂载文件系统
我们访问文件时是根据路径来访问的,所以在使用文件系统前,还需要将存储文件的设备与一个路径关联起来,这就是文件系统的挂载,通过函数vfs_mount()实现。之后就可以通过这个路径来访问存储设备。
卸载文件系统
当某个文件系统不再需要使用时,可以通过函数vfs_unmount()卸载掉。
文件系统操作接口
接口 | 说明 |
---|---|
vfs_init | 初始化虚拟文件系统 |
vfs_register | 注册某种类型的文件系统到VFS中 |
vfs_mkfs | 将设备格式化成某种文件系统 |
vfs_mount | 将设备挂载到某个路径上 |
vfs_unmount | 卸载某个路径上的文件系统 |
vfs_init
该函数用于注册某种类型的文件系统到VFS中,函数原型如下:
int vfs_init(void);
参数 | 说明 |
---|---|
无 | 无 |
返回 | 说明 |
0 | 初始化成功 |
vfs_register
该函数用于注册某种类型的文件系统到VFS中,函数原型如下:
int vfs_register(const struct vfs_filesystem_ops *ops);
参数 | 说明 |
---|---|
ops | VFS操作结构体,该结构体中包含了实际文件系统对应的操作接口,如mount/unmount/open/close/read/write等。 每个具体的文件系统不一定支持所有接口。 |
返回 | 说明 |
0 | 注册成功 |
-1 | 注册失败 |
vfs_mkfs
该函数用于将设备格式化成某种文件系统,函数原型如下:
int vfs_mkfs(const char *fs_name, const char *device_name);
参数 | 说明 |
---|---|
fs_name | 文件系统类型名字,例如:对于FATFS名字为fat,对于JFFS2文件系统名字为jffs2,对于YAFFS文件系统名字为yaffs;对于Littlefs文件系统名字为littlefs;CUTEFS、DEVFS、NFS不需要格式化,不支持此操作 |
device_name | 设备名 |
返回 | 说明 |
0 | 格式化成功 |
其它值 | 格式化失败 |
vfs_mount
该函数用于将设备挂载到某个路径上,函数原型如下:
int vfs_mount(const char *device_name,
const char *path,
const char *filesystemtype,
unsigned long rwflag,
const void *data);
参数 | 说明 |
---|---|
device_name | 设备名 |
path | 挂载路径 |
filesystemtype | 文件系统类型 |
rwflag | 读写设备的标记,暂未使用该参数 |
data | 私有数据 |
返回 | 说明 |
0 | 挂载成功 |
其它值 | 挂载失败 |
vfs_unmount
该函数用于将某个路径上的文件系统卸载掉,函数原型如下:
int vfs_unmount(const char *path);
参数 | 说明 |
---|---|
path | 文件系统的路径(与挂载时的路径相同) |
返回 | 说明 |
0 | 卸载成功 |
其它值 | 卸载失败 |
POSIX文件操作接口
接口 | 说明 |
---|---|
open | 打开指定文件,并返回文件描述符 |
close | 关闭文件 |
read | 从文件中读取指定长度的数据 |
write | 写指定长度的数据到文件 |
lseek | 设置读写位置 |
rename | 重命名文件 |
unlink | 移除文件 |
stat | 根据文件路径获取文件信息 |
fstat | 根据文件描述符获取文件信息 |
fsync | 同步缓存数据到存储设备 |
fcntl | 对文件描述符的控制操作 |
ioctl | 对(设备)文件的控制操作 |
access | 查看用户访问权限 |
open
该函数用于打开指定文件,并返回文件描述符,函数原型如下:
int open(const char *file, int flags, ...);
参数 | 说明 |
---|---|
file | 文件名 |
flags | 打开文件的方式 |
... | 可变参数 |
返回 | 说明 |
非负值 | 文件描述符 |
-1 | 打开失败,errno可通过os_get_errno()查看 |
close
该函数用于关闭指定文件,函数原型如下:
int close(int fd);
参数 | 说明 |
---|---|
fd | 文件描述符 |
返回 | 说明 |
0 | 关闭成功 |
-1 | 关闭失败,errno可通过os_get_errno()查看 |
read
该函数用于从文件中读取指定长度的数据,函数原型如下:
int read(int fd, void *buf, size_t nbyte);
参数 | 说明 |
---|---|
fd | 文件描述符 |
buf | 保存读取到数据的缓存区 |
nbyte | 期望读取数据的长度 |
返回 | 说明 |
正数 | 实际读取到数据的长度 |
0 | 已到达文件尾部 |
-1 | 失败,errno可通过os_get_errno()查看 |
write
该函数用于将将指定长度的数据写入文件,函数原型如下:
int write(int fd, const void *buf, size_t nbyte);
参数 | 说明 |
---|---|
fd | 文件描述符 |
buf | 待写入数据的地址 |
nbyte | 写入数据的长度 |
返回 | 说明 |
非负数 | 实际写入数据的长度 |
-1 | 写入失败,errno可通过os_get_errno()查看 |
lseek
该函数用于修改文件的读写位置,函数原型如下:
off_t lseek(int fildes, off_t offset, int whence);
参数 | 说明 |
---|---|
fildes | 文件描述符 |
offset | 位置偏移量 |
whence | 偏移的位置,包括SEEK_SET、SEEK_CUR、SEEK_END |
返回 | 说明 |
非负数 | 当前读写位置距离文件头部的字节数 |
-1 | 失败,errno可通过os_get_errno()查看 |
rename
该函数用于重命名文件,按照如下语义实现:a)将一个文件重命名为一个目录,或将一个目录重命名为一个文件将会失败;b)将旧文件重命名为一个已经存在的新文件将会成功,原本存在的新文件会先被删除;c)将旧目录重命名为一个已经存在的、且非空的新目录会失败;d)将旧目录重命名为一个已经存在的、空的新目录会成功,原本存在的新目录会先被删除;e)新路径以旧路径作为前缀会失败;f)新路径包含不存在的父目录会失败。注意:在某些文件系统上,该操作无法保证原子性。函数原型如下:
int rename(const char *old, const char *new);
参数 | 说明 |
---|---|
old | 旧文件名 |
new | 新文件名 |
返回 | 说明 |
0 | 成功 |
-1 | 失败,errno可通过os_get_errno()查看 |
unlink
该函数用于移除文件,函数原型如下:
int unlink(const char *path);
参数 | 说明 |
---|---|
path | 文件名 |
返回 | 说明 |
0 | 成功 |
-1 | 失败,errno可通过os_get_errno()查看 |
stat
该函数用于根据文件路径获取文件状态信息,函数原型如下:
int stat(const char *path, struct stat *sbuf);
参数 | 说明 |
---|---|
path | 文件名(文件路径) |
sbuf | 用于保存获取到的文件信息的缓存区地址 |
返回 | 说明 |
0 | 成功 |
-1 | 失败,errno可通过os_get_errno()查看 |
fstat
该函数用于根据文件描述符获取文件状态信息,函数原型如下:
int fstat(int fd, struct stat *sbuf);
参数 | 说明 |
---|---|
fd | 文件描述符 |
sbuf | 用于保存获取到的文件信息的缓存区地址 |
返回 | 说明 |
0 | 成功 |
-1 | 失败,errno可通过os_get_errno()查看 |
fsync
该函数用于同步缓存数据到存储设备,函数原型如下:
int fsync(int fd);
参数 | 说明 |
---|---|
fd | 文件描述符 |
返回 | 说明 |
0 | 成功 |
-1 | 失败,errno可通过os_get_errno()查看 |
fcntl
该函数用于设置或者获取文件描述符的特殊属性,函数原型如下:
int fcntl(int fd, int flag, ...);
参数 | 说明 |
---|---|
fd | 文件描述符 |
flag | 控制命令,目前支持F_GETFL、F_SETFL |
... | 可变参数 |
返回 | 说明 |
非负数 | 若是设置属性,正确时返回0;若是读取属性,正确时返回该属性值 |
-1 | 失败,errno可通过os_get_errno()查看 |
ioctl
该函数用于对(设备)文件的控制操作,函数原型如下:
int ioctl(int fd, unsigned long request, ...);
参数 | 说明 |
---|---|
fd | 文件描述符 |
request | 控制命令,依赖于具体的(设备)文件的支持 |
... | 可变参数 |
返回 | 说明 |
非负数 | 取决于具体的命令 |
-1 | 失败,errno可通过os_get_errno()查看 |
access
该函数用于查看是否有权限访问指定文件,函数原型如下:
int access(const char *pathname, int mode);
参数 | 说明 |
---|---|
pathname | 文件名(文件路径) |
mode | 检查模式,该参数暂未使用 |
返回 | 说明 |
0 | 成功,目前仅支持查看文件是否存在,忽略读、写、可执行权限 |
-1 | 失败,errno可通过os_get_errno()查看 |
POSIX目录操作接口
接口 | 说明 |
---|---|
mkdir | 创建目录 |
rmdir | 删除目录 |
opendir | 打开目录 |
closedir | 关闭目录 |
readdir | 读取目录内容 |
telldir | 获取与目录流相关联的当前位置 |
seekdir | 设置下一个读取目录(readdir)操作的位置 |
rewinddir | 重置目录流的读取位置到目录开头 |
getcwd | 获取当前工作路径 |
chdir | 修改当前工作路径 |
mkdir
该函数用于创建目录,函数原型如下:
int mkdir(const char *path, mode_t mode);
参数 | 说明 |
---|---|
path | 路径 |
mode | 权限,该参数暂未使用 |
返回 | 说明 |
0 | 成功 |
-1 | 失败,errno可通过os_get_errno()查看 |
rmdir
该函数用于删除目录,函数原型如下:
int rmdir(const char *pathname);
参数 | 说明 |
---|---|
pathname | 路径 |
返回 | 说明 |
0 | 成功 |
-1 | 失败,errno可通过os_get_errno()查看 |
opendir
该函数用于打开目录,函数原型如下:
DIR *opendir(const char *path)
参数 | 说明 |
---|---|
path | 路径 |
返回 | 说明 |
非NULL值 | 打开成功,返回目录流指针 |
NULL | 打开失败,errno可通过os_get_errno()查看 |
closedir
该函数用于关闭目录,函数原型如下:
int closedir(DIR *pdir);
参数 | 说明 |
---|---|
pdir | 目录流指针 |
返回 | 说明 |
0 | 关闭成功 |
-1 | 关闭失败,errno可通过os_get_errno()查看 |
readdir
该函数用于读取目录内容,且每调用一次该函数,则目录条目的指针就会移向下一个,函数原型如下:
struct dirent *readdir(DIR *pdir);
参数 | 说明 |
---|---|
pdir | 目录流指针 |
返回 | 说明 |
非NULL值 | 目录条目的指针 |
NULL | 错误或者已经到达目录结尾,errno可通过os_get_errno()查看 |
telldir
该函数用于获取与目录流相关联的当前位置,函数原型如下:
long telldir(DIR *pdir);
参数 | 说明 |
---|---|
pdir | 目录流指针 |
返回 | 说明 |
其它值 | 该返回值记录着一个目录流的当前位置,代表距离目录文件开头的偏移量。此偏移量可以用于seekdir()函数 |
-1 | 错误,errno可通过os_get_errno()查看 |
seekdir
该函数用于设置下一个读取目录(readdir)操作的位置,函数原型如下:
void seekdir(DIR *pdir, long ofst);
参数 | 说明 |
---|---|
pdir | 目录流指针 |
ofst | 偏移量 |
rewinddir
该函数用于重置目录流的读取位置到目录开头,函数原型如下:
void rewinddir(DIR *pdir);
参数 | 说明 |
---|---|
pdir | 目录流指针 |
getcwd
该函数用于获取当前工作路径,函数原型如下:
char *getcwd(char *buf, size_t size);
参数 | 说明 |
---|---|
buf | 保存路径的缓存区 |
size | 缓存区的大小 |
返回 | 说明 |
char * | 缓存区的指针 |
chdir
该函数用于修改当前工作路径,函数原型如下:
int chdir(const char *path);
参数 | 说明 |
---|---|
path | 新路径 |
返回 | 说明 |
0 | 成功 |
-1 | 失败,errno可通过os_get_errno()查看 |
文件操作shell命令
支持常用的文件操作命令,具体如下:
命令 | 用法 | 说明 |
---|---|---|
ls | ls [DIRNAME] | 列出DIRNAME目录下的信息;若无参数DIRNAME,则列出当前目录下信息 |
cp | cp <SOURCE> <DEST> | 把SOURCE文件或文件夹复制到DEST |
mv | mv <SOURCE> <DEST> | 把SOURCE文件或文件夹重命名成DEST |
echo | echo <string> > [FILE] echo <string> >> [FILE] |
把字符串sting写入到FILE中;若无参数FILE,则创建FILE后写入 把字符串sting追加写入到FILE中;若无参数FILE,则创建FILE后写入 |
cat | cat <FILE> ... | 查看文件FILE的内容,可同时查看多个文件内容 |
rm | rm <FILE> ... | 删除文件或文件夹的内容,可同时删除多个;删除文件夹前,需确认该文件夹为空 |
cd | cd [PATH] | 切换到PATH所在路径;若无参数PATH,则仍为当前路径 |
pwd | pwd | 显示当前工作路径 |
mkdir | mkdir <DIRNAME> | 创建目录DIRNAME |
另外还支持几个跟文件系统相关的命令,具体如下:
命令 | 用法 | 说明 |
---|---|---|
mkfs | mkfs [-t TYPE] <DEVICENAME> | 在设备DEVICENAME上创建TYPE类型的文件系统;当前TYPE支持fat、jffs2、yaffs、littlefs |
df | df [PATH] | 查看磁盘剩余空间 |
配置选项
OneOS在使用文件系统时提供了功能裁剪的配置,具体配置如下图所示:
配置项 | 说明 |
---|---|
Enable virtual file system | 使能虚拟文件系统功能,如果不使能该功能,虚拟文件系统相关的源代码就不会编译 |
The max number of mounted file system | 最大可挂载文件系统的数量,默认值为4 |
The max number of file system type | 最大可注册的文件系统的种类,默认值为4 |
The max number of opened files | 最大可同时打开文件的数量,默认值为16 |
Enable DevFS file system | 使能DevFS文件系统,如果不使能该选项,DevFS文件系统相关的源代码就不会编译 |
Enable CuteFs file system | 使能CuteFs文件系统,如果不使能该选项,CuteFs文件系统相关的源代码就不会编译 |
Enable JFFS2 | 使能JFFS2文件系统,如果不使能该选项,JFFS2文件系统相关的源代码就不会编译 |
Enable Yaffs2 file system | 使能Yaffs2文件系统,如果不使能该选项,Yaffs2文件系统相关的源代码就不会编译 |
Enable FatFs | 使能FatFs文件系统,如果不使能该选项,FatFs文件系统相关的源代码就不会编译 |
Enable NFS v3 client file system | 使能NFS文件系统,如果不使能该选项,NFS文件系统相关的源代码就不会编译 |
Enable little filesystem | 使能littlefs文件系统,如果不使能该选项,littlefs文件系统相关的源代码就不会编译 |
使用示例
分区挂载演示示例
本例演示了将一个存储分区挂载到系统下的方法
如上图所示,预先在外部norflash准备好一个名为“filesystem”分区,将其挂载到系统下并格式化为fatfs格式,先决条件需要先使能FatFs文件系统
#include <board.h>
#include <os_task.h>
#include <shell.h>
#define TEST_TAG "TEST"
#if defined(OS_USING_VFS)
#include <vfs_fs.h>
#endif
#ifdef OS_USING_VFS_FATFS
#define OS_FS_PART_NAME "filesystem"
static void mount_fatfs(void)
{
if (fal_blk_device_create(OS_FS_PART_NAME))
{
LOG_W(TEST_TAG, "Create a block device on the %s partition of flash successful.", OS_FS_PART_NAME);
}
else
{
LOG_E(TEST_TAG, "Can't create a block device on '%s' partition.", OS_FS_PART_NAME);
}
if (vfs_mkfs("fat", OS_FS_PART_NAME) == 0)
{
LOG_W(TEST_TAG, "Make format on the %s partition of flash successful.", OS_FS_PART_NAME);
}
else
{
LOG_E(TEST_TAG, "Can't make format on '%s' partition.", OS_FS_PART_NAME);
}
if (vfs_mount(OS_FS_PART_NAME, "/", "fat", 0, 0) == 0)
{
LOG_W(TEST_TAG, "FAT filesystem mount successful.");
}
else
{
LOG_E(TEST_TAG, "FAT filesystem mount fail.");
LOG_E(TEST_TAG, "You should mkfs first, then reset board ! cmd: mkfs -t fat %s", OS_FS_PART_NAME);
}
}
#endif
SH_CMD_EXPORT(test_mount, mount_fatfs, "test for mount partition");
运行结果如下:
sh />test_mount
W/TEST: Create a block device on the filesystem partition of flash successful.
W/TEST: Make format on the filesystem partition of flash successful.
W/TEST: FAT filesystem mount successful.
文件操作接口使用示例
本例演示了文件操作常用接口的使用方法,先决条件需要先挂载了分区
#include <oneos_config.h>
#include <shell.h>
#include <vfs_posix.h>
#include <unistd.h>
#include <fcntl.h>
#define TEST_TAG "TEST"
#define FILE_NAME "test.txt"
#define FILE_NAME_NEW "test_new.txt"
void file_operation_sample(void)
{
int fd, size, str_len;
char *str[3] = {"1234567890", "ABCDEFGHIJ", "abcdefghij"};
char bufread[35];
off_t offset = 0;
char* str_ptr;
struct stat filestat;
fd = open(FILE_NAME, O_RDWR | O_CREAT);
if (fd < 0)
{
LOG_E(TEST_TAG, "open file err");
return;
}
else
{
LOG_W(TEST_TAG, "open(create) file:%s", FILE_NAME);
str_ptr = str[0];
str_len = strlen(str_ptr);
size = write(fd, str_ptr, str_len);
LOG_W(TEST_TAG, "write %d byte from offset %d :%s", size, offset, str_ptr);
}
offset = 20;
if (lseek(fd, offset, SEEK_SET) != -1)
{
str_ptr = str[1];
str_len = strlen(str_ptr);
size = write(fd, str_ptr, str_len);
LOG_W(TEST_TAG, "write %d byte from offset %d :%s", size, offset, str_ptr);
}
offset = 10;
if (lseek(fd, offset, SEEK_SET) != -1)
{
str_ptr = str[2];
str_len = strlen(str_ptr);
size = write(fd, str_ptr, str_len);
LOG_W(TEST_TAG, "write %d byte from offset %d :%s", size, offset, str_ptr);
}
offset = 0;
if (lseek(fd, offset, SEEK_SET) != -1)
{
memset(bufread, 0, sizeof(bufread));
size = read(fd, bufread, sizeof(bufread));
LOG_W(TEST_TAG, "read %d byte from offset %d :%s", size, offset, bufread);
}
if(fstat(fd, &filestat) != -1)
{
LOG_W(TEST_TAG, "the filesize of %s is :%d", FILE_NAME, filestat.st_size);
}
if(close(fd) != -1)
{
LOG_W(TEST_TAG, "close file:%s", FILE_NAME);
}
if(rename(FILE_NAME, FILE_NAME_NEW) != -1)
{
LOG_W(TEST_TAG, "rename %s to %s", FILE_NAME, FILE_NAME_NEW);
}
if(stat(FILE_NAME_NEW, &filestat) != -1)
{
LOG_W(TEST_TAG, "the filesize of %s is :%d", FILE_NAME_NEW, filestat.st_size);
}
if (unlink(FILE_NAME_NEW) != -1)
{
LOG_W(TEST_TAG, "rm file:%s", FILE_NAME_NEW);
}
}
SH_CMD_EXPORT(test_file, file_operation_sample, "test for file operation");
运行结果如下:
sh />test_file
W/TEST: open(create) file:test.txt
W/TEST: write 10 byte from offset 0 :1234567890
W/TEST: write 10 byte from offset 20 :ABCDEFGHIJ
W/TEST: write 10 byte from offset 10 :abcdefghij
W/TEST: read 30 byte from offset 0 :1234567890abcdefghijABCDEFGHIJ
W/TEST: the filesize of test.txt is :30
W/TEST: close file:test.txt
W/TEST: rename test.txt to test_new.txt
W/TEST: the filesize of test_new.txt is :30
W/TEST: rm file:test_new.txt
目录操作接口使用示例
本例演示了常用目录操作接口的使用方法,先决条件需要先挂载了分区
#include <oneos_config.h>
#include <shell.h>
#include <vfs_posix.h>
#include <unistd.h>
#include <fcntl.h>
#define TEST_TAG "TEST"
#define DIR_NAME "/dir_test"
#define FILE_NUM 3
static char *file_name[FILE_NUM] = {"test1.txt", "test2.txt", "test3.txt"};
static void dir_operation_sample(void)
{
int i = 0;
int fd;
DIR *dirp;
int save_offset = 0;
struct dirent *dp;
char bufread[32];
char *str = "test";
if(mkdir(DIR_NAME, 0x777) == -1)
{
LOG_E(TEST_TAG, "mkdir err");
return;
}
else
{
LOG_W(TEST_TAG, "mkdir:%s", DIR_NAME);
}
if (chdir(DIR_NAME) != -1)
{
LOG_W(TEST_TAG, "chdir:%s", DIR_NAME);
}
getcwd(bufread, sizeof(bufread));
LOG_W(TEST_TAG, "getcwd:%s", bufread);
dirp = opendir(DIR_NAME);
dp = readdir(dirp);
if (dp == NULL)
{
LOG_W(TEST_TAG, "there is no dir entry");
}
closedir(dirp);
for (i = 0; i < FILE_NUM; i++)
{
fd = open(file_name[i], O_RDWR | O_CREAT);
if (fd != -1)
{
LOG_W(TEST_TAG, "open(create) file:%s", file_name[i]);
write(fd, str, strlen(str));
close(fd);
}
}
i = 0;
dirp = opendir(DIR_NAME);
for (dp = readdir(dirp); dp != OS_NULL; dp = readdir(dirp))
{
i++;
LOG_W(TEST_TAG, "readdir: %s (type:%d)", dp->d_name, dp->d_type);
if (i == 2)
{
save_offset = telldir(dirp);
LOG_W(TEST_TAG, "save the 2nd dir entry, it's offset:%d", save_offset);
}
}
LOG_W(TEST_TAG, "seek to the 2nd dir entry, then readdir from it");
seekdir(dirp, save_offset);
for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
{
LOG_W(TEST_TAG, "readdir: %s (type:%d)", dp->d_name, dp->d_type);
}
closedir(dirp);
for (i = 0; i < FILE_NUM; i++)
{
LOG_W(TEST_TAG, "rm file:%s", file_name[i]);
unlink(file_name[i]);
}
if (chdir("/") != -1)
{
LOG_W(TEST_TAG, "chdir:/");
}
getcwd(bufread, sizeof(bufread));
LOG_W(TEST_TAG, "getcwd:%s", bufread);
LOG_W(TEST_TAG, "rm dir:%s", DIR_NAME);
unlink(DIR_NAME);
}
SH_CMD_EXPORT(test_dir, dir_operation_sample, "test for dir operation");
运行结果如下:
sh />test_dir
W/TEST: mkdir:/dir_test
W/TEST: chdir:/dir_test
W/TEST: getcwd:/dir_test
W/TEST: there is no dir entry
W/TEST: open(create) file:test1.txt
W/TEST: open(create) file:test2.txt
W/TEST: open(create) file:test3.txt
W/TEST: readdir: test1.txt (type:1)
W/TEST: readdir: test2.txt (type:1)
W/TEST: save the 2nd dir entry, it's offset:260
W/TEST: readdir: test3.txt (type:1)
W/TEST: seek to the 2nd dir entry, then readdir from it
W/TEST: readdir: test2.txt (type:1)
W/TEST: readdir: test3.txt (type:1)
W/TEST: rm file:test1.txt
W/TEST: rm file:test2.txt
W/TEST: rm file:test3.txt
W/TEST: chdir:/
W/TEST: getcwd:/
W/TEST: rm dir:/dir_test
文件操作shell命令使用示例
本例演示了常用shell命令的使用方法,包括ls/echo/cat/mkdir/pwd/rename/rm/cd等,先决条件需要先挂载了分区
sh />ls
Directory /:
sh />echo 111 > test1.txt
sh />ls
Directory /:
test1.txt 3
sh />cat test1.txt
111
sh />mkdir dir_test
sh />ls
Directory /:
test1.txt 3
dir_test <DIR>
sh />cd dir_test
sh /dir_test>echo 222 > test2.txt
sh /dir_test>ls
Directory /dir_test:
test2.txt 3
sh /dir_test>cat test2.txt
222
sh /dir_test>pwd
/dir_test
sh /dir_test>mv test2.txt test3.txt
test2.txt => test3.txt
sh /dir_test>ls
Directory /dir_test:
test3.txt 3
sh /dir_test>cat test3.txt
222
sh /dir_test>rm test3.txt
sh /dir_test>ls
Directory /dir_test:
sh /dir_test>cd ..
sh />ls
Directory /:
test1.txt 3
dir_test <DIR>
sh />rm dir_test
sh />ls
Directory /:
test1.txt 3
sh />