一、Linux文件操作
Linux的文件系统API主要涉及创建、打开、读写、定位、关闭文件
创建
int creat(const char *filename, mode_t mode);
-
mode: 代表新建文件的存取权限,需要和umask相与才能确定最终权限(mode&umask)。
-
umask代表文件在创建时需要去掉的存取权限
打开
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
- flags可以是一个值或几个值的组合,其中
O_RDONLY
、O_WRONLY
、O_RDWR
只能使用一个 - 如果使用了
O_CREATE
, 则需要加mode参数表示文件的访问权限
读写
int read(int fd, const void *buf, size_t length);
int write(int fd, const void *buf, size_t length);
- buf指向缓冲区的指针,length代表缓冲区大小(byte)
- read()是从fd中读取length字节到buf中,返回实际读取的字节数
- write()是把length个字节从buf写到fd中,返回实际写入的字节数
定位
int lseek(int fd, offset_t offset, int whence);
- 讲文件的读写指针相对whence移动offset字节,成功返回读写指针相对于文件头的位置
- whence代表相对位置,可以使用以下的值:
- offset可以取负值,代表相对于当前位置向前移
关闭
int close(int fd);
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#define LENGTH 100
main()
{
int fd, len;
char str[LENGTH];
/* 创建并打开文件 */
fd = open("hello.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); /*
if (fd) {
/* 写入字符串 */
write(fd, "Hello World", strlen("Hello World")); /*
/* 关闭文件 */
close(fd);
}
fd = open("hello.txt", O_RDWR);
/* 读取文件内容 */
len = read(fd, str, LENGTH);
str[len] = '\0';
printf("%s\n", str);
close(fd);
}
二、LInux文件系统
1. 目录结构
/bin: 包含基本命令,如ls、cp、mkdir等,这个目录中的文件都是可以执行的
/sbin: 大多涉及到系统管理的命令,如modprobe、hwclock、ifconfig等,也都是可以执行的
/dev: 设备文件存储目录,应用程序通过对这些文件的读写和控制来访问实际的设备
/etc: 存放系统和一些服务器配置文件,如用户账号和密码配置文件。
/lib: 存放系统库目录
/mnt: 用于存放挂载存储设备
/opt: option可选,有些软件包安装在此处
/proc: 存放操作系统运行时的进程及内核信息的伪目录,实际的信息在内存之中
/tmp: 用来存放临时文件
/usr: 存放程序目录,如用户命令、用户库等
var:存放经常变动的内容,如存放系统日志
/sys: sysfs文件系统映射在此目录,Linux设备驱动模型中的总线、驱动和设备都可以在此种找到对应的节点
2. 文件系统与设备驱动
1. 应用程序VFS(虚拟文件系统)之间的接口就是系统调用,即Linux文件系统(或C库)的API,包括read()
、write()
等函数
2. VFS与文件系统以及设备文件之间的接口是file_operations
结构体成员函数,这个结构体实现了相关设备的xxx_open()
、xxx_write()
、xxx_read()
等函数
3. 块设备有两种访问方式
- 第一种是不通过文件系统访问直接访问裸设备,内核同一实现了def_blk_fops这一file_operations
- 第二种则是通过文件系统访问块设备,file_operations的实现位于文件系统内部,文件系统给会将针对文件的读写转为针对块设备原始扇区的读写。如ext2、fat等文件系统会实现针对VFS的file_operations结构体成员函数。
file结构体
当应用程序通过VFS调用open函数打开一个文件时,系统会为该文件在内核中关联一个file结构体。这个结构体在文件打开时由内核创建,并且对这个文件进行任何操作的函数(如read、write、seek等)都会得到这个结构体,在这个文件的所有实例关闭后该结构体会被内核释放。
struct file {
union {
struct llist_node fu_llist;
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path;
#define f_dentry f_path.dentry
struct inode *f_inode; /* cached value */
const struct file_operations*f_op; /* 和文件关联的操作 */
/*
* Protects f_ep_links, f_flags.
* Must not be taken from IRQ context.
*/
spinlock_t f_lock;
atomic_long_t f_count;
unsigned int f_flags; /* 文件标志,如 O_RDONLY 、 O_NONBLOCK 、 O_SYNC*/
fmode_t f_mode; /* 文件读 / 写模式, FMODE_READ 和 FMODE_WRITE*/
struct mutex f_pos_lock;
loff_t f_pos; /* 当前读写位置 */
struct fown_struct f_owner;
const struct cred *f_cred;
struct file_ra_statef_ra;
u64 f_version;
#ifdef CONfiG_SECURITY
void *f_security;
#endif
/* needed for tty driver, and maybe others */
void *private_data; /* 文件私有数据 */
#ifdef CONfiG_EPOLL
/* Used by fs/eventpoll.c to link all the hooks to this file */
struct list_head f_ep_links;
struct list_head f_tfile_llink;
#endif /* #ifdef CONfiG_EPOLL */
struct address_space*f_mapping;
}__attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
inode结构体
inode结构体包含文件自身的属性信息,包括访问权限、所属组、大小、生成时间等等
struct inode {
...
umode_t i_mode; /* inode 的权限 */
uid_t i_uid; /* inode 拥有者的 id */
gid_t i_gid; /* inode 所属的群组 id */
dev_t i_rdev; /* 若是设备文件,此字段将记录设备的设备号 */
loff_t i_size; /* inode 所代表的文件大小 */
struct timespec i_atime; /* inode 最近一次的存取时间 */
struct timespec i_mtime; /* inode 最近一次的修改时间 */
struct timespec i_ctime; /* inode 的产生时间 */
unsigned int i_blkbits;
blkcnt_t i_blocks; /* inode 所使用的 block 数,一个 block 为 512 字节 */
union {
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
/* 若是块设备,为其对应的 block_device 结构体指针 */
struct cdev *i_cdev; /* 若是字符设备,为其对应的 cdev 结构体指针 */
}
...
};