玖叶教程网

前端编程开发入门

Linux基础知识(三)(linux 基础教程)

本篇介绍一些Linux文件操作API 函数的使用.

1.基本概念

1.1 linux 下一切皆文件(网络设备除外)

(1) 普通文件

(2) 目录

(3) 硬件设备

- 控制台 /dev/console

- 标准输入输出设备 /dev/tty

(4) 软链接文件

(5) 硬链接文件

1.2 文件操作 API

文件操作 API主要分为Linux系统API和标C库API, 其区别分别体现在效率和移植行上.

(1) linux :open read write close lseek ...( 效率高)

(2) 标 C 库函数 :fopen fread fwrite fclose fseek ...( 移植性强)

2. Linux的文件基本操作 API介绍

2.1 创建文件

creat 函数 : 用于创建文件

creat (const char* pathname, mode_t mode)

等价于 open 函数使用 flags 参数为 O_CREAT O_WRONLY O_REUNC

2.2 打开文件

open 函数 :用于打开文件, 创建文件

int open(const char* pathname, int flags, mode_t mode)
filename : 要打开文件的名称(包含路径)
flags : 以下三个参数必须选其中一个
- O_RONLY
- O_WRONLY
- O_RDWR
其他参数
O_APPEND : 追加写入
O_CREAT : 如果打开文件不存在则创建
O_EXCL : 检测要创建的文件是否存在, 一般情况下和 O_CREAT 联合使用, 如果要创建文件已存在, 则返回失败
O_TRUNC:文件截短为 0 长度
mode : 创建文件时的读写权限
返回值:失败返回-1, 错误编码 errno, 成功返回文件描述符

2.3 关闭文件

close函数 : 用于关闭文件

int close(int fd)
fd : 要关闭文件对应的文件描述符, 即 open 函数的返回值
返回值 : 失败 erron, 成功 0

2.4 写文件

write函数 : 用于写文件

ssize_t write(int fd, const void* buf, size_t count)
fd : 要操作的文件
buf : 数据源
count : 期望写入的字节个数
返回值 : 成功 返回实际写入字节个数,返回 0 表示没有写入任何信息,失败返回errno

2.5 读文件

read函数 : 用于读文件

ssize_t read(int fd, void* buf, size_t count) 
fd : 要操作的文件
buf : 从文件中读取数据的写入位置
count : 期望读取的字节个数
返回值 : 成功 返回实际读取字节个数, 返回 0 代表读到这个文件的末尾, 失败返回-1

3. Linux的文件相关操作 API介绍

3.1 文件偏移量

每个打开的文件都记录着当前读写位置, 打开文件时读写位置是0, 表示文件开头, 通常读

写多少个字节就会将读写位置往后移多少个字节, 这个读写位置称作文件偏移offset, 文件

表中的 offset 决定读写文件的具体位置, open 文件时如果没有O_APPEND, offset=0.

lseek 函数 : 用于改变文件表中 offset 的取值

off_t lseek(int fd, off_t offset, int whence)
fd : 操作的文件
offset : 偏移量
whence : 偏移的起始位置, 有三个取值
- SEEK_SET, 从文件头开始计算
- SEEK_CUR, 从当前位置计算偏移
- SEEK_END, 从文件末尾计算偏移
返回值 : 成功, 移动到的目标位置与文件头的距离, 失败返回-1

(1) lseek 计算文件的长度

len=lseek(fd,0,SEEK_END);

(2) lseek 移动的目标可以超越文件的末尾

后续执行写入操作会在文件中形成空洞文件, 空洞文件不占磁盘, 但被算在文件大小内

3.2 文件描述符复制

打开现存文件或新建文件时, 内核会返回一个文件描述符, 每一个文件描述符会与一个打开文件相对应, 不同的文件描述符也会指向同一个文件

dup / dup2函数 : 用于复制文件描述符, 不会复制文件表, 出现多个文件描述符

int dup(int oldfd)
oldfd : 要复制的文件描述符
返回值 : 新的文件描述符, 操作系统选取未使用的最小文件描述符
int dup2(int oldfd, int newfd)
oldfd : 要复制的文件描述符
newfd : 指定新的文件描述符, 如果 newfd 已经被使用, 系统会强行关闭对应的文件, 使得
newfd 处于未使用状态

实际编程过程中, dup / dup2函数通常用于重定向标准输出和标准出错

3.3 文件竞争

fcntl函数 : 用于对已打开的文件描述符进行各种控制操作以改变已打开文件的的各种属性

fcntl函数可以实现很多功能, 但其主要功能是文件记录锁, 解决多个进程同时竞争一个文件的问题

int fcntl(inf fd, int cmd, ... /* arg */)
fd : 文件描述符
cmd : 需要执行的具体操作
 - F_GETLK : 测试 lock 所表示的所是否可以加, 若可加 lock.l_type 设置成 F_UNLCK, 否则通过 lock 返回当前锁的信息
 - F_SETLK : 设置所的类型
 - F_SETLkW : 加锁等待, 加锁不成功则一直等待, 除非被信号打断 返回 -1 
arg : 针对cmd的值, fcntl能够接受第三个参 arg

当fcntl用于管理文件记录锁的操作时,第三个参数指向一个stsuct flock *lock的结构体构体

struct flock 
{ 
 short_l_type; /*锁的类型 F_RDLCK(读锁)F_WRLCK(写锁) F_UNLCK(解锁)
 short_l_whence; /*偏移量的起始位置:SEEK_SET,SEEK_CUR,SEEK_END*/ 
 off_t_l_start; /*加锁的起始偏移*/ 
 off_t_l_len; /*上锁字节*/ 
 pid_t_l_pid; /*锁的属主进程ID */ 
}; 

(1) 锁机制是建议性锁, 而不是强制性锁

(2) 读锁 (共享锁), 写锁(独占锁)

(3) 锁机制并不是真正把文件锁起来, 加锁不成功, 程序逻辑不去执行相应的文件操作

3.4 文件属性获取

struct stat 
{ 
 dev_t st_dev; /* 文件所在设备的标识 */ 
 ino_t st_ino; /* 文件结点号 */ 
 mode_t st_mode; /* 文件保护模式 */ 
 nlink_t st_nlink; /* 硬连接数 */ 
 uid_t st_uid; /* 文件用户标识 */ 
 gid_t st_gid; /* 文件用户组标识 */ 
 dev_t st_rdev; /* 文件所表示的特殊设备文件的设备标识 */ 
 off_t st_size; /* 总大小,字节为单位 */ 
 blksize_t st_blksize; /* 文件系统的块大小 */ 
 blkcnt_t st_blocks; /* 分配给文件的块的数量,512字节为单元 */ 
 time_t st_atime; /* 最后访问时间 */ 
 time_t st_mtime; /* 最后修改时间 */ 
 time_t st_ctime; /* 最后状态改变时间 */ 
}; 

(1) stat 函数 : 获取文件的详细信息

int stat(const char *path, struct stat *buf);
path : 要获取属性相关信息的文件名称(包含路径), 不需要打开文件, 直接给文件路径
buf : 文件属性结构体, 为传出参数

(2) fstat函数 :

int fstat(int fd, struct stat *buf)
path : 文件描述符
buf : 文件属性结构体, 为传出参数

(3) lstat函数 : 获取软链接文件本身的信息

int lstat(const char *path, struct stat *buf)
path : 要获取属性相关信息的文件名称(包含路径), 不需要打开文件, 直接给文件路径
buf : 文件属性结构体, 为传出参数

(4) stat / lstat / fstat之间的区别

- fstat 函数 : 系统调用的是一个 "文件描述符", 而另外两个则直接接收"文件路径", 文件描述符是我们用 open 系统调用后得到的, 而文件全路径直接写就可以了

- stat 函数与 lstat 函数的区别 : 当一个文件是符号链接时, lstat 函数返回的是该符号链接本身的信息;而 stat 函数返回的是该链接指向文件的信息

3.5 文件属性修改

(1) chmod函数 : 修改文件的权限

int chmod(const char *pathname, mode_t mode)
pathname : 要修改权限的文件名称(包含路径)
mode_t : 要修改什么全权限, 可读可写

(2) access函数 : 测试文件的访问, 以及判断文件是否存在

int access(const char *pathname, int mode)
pathname : 要测试文件名称
mode: F_OK, 测试文件是否存在
 R_ OK, 测试文件是否可读
 W_OK, 测试文件是否可写
 X_OK, 测试文件是否可执行

3.6 文件长度修改

truncate函数 : 修改文件的长度为指定的字节, 截断丢弃数据, 加长默认补0

int truncate(const char * path, off_t length)
path : 需要操作的文件名称
length : 需要修改的长度

3.7 文件映射

(1) mmap函数 : 将一个文件或者对象映射进内存, 后续操作可以变成操作内存

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
addr : 可以指定映射的首地址, 一般情况下给 NULL, 交给内核, 让内核来分配指定地址
size : 分配映射的内存大小, 映射时 size 取值以页(4096B-->4096 个字节) 为单位
prot : 分配映射内存权限, 常见取值是 PORT_READ | PORT_WRITE
flags : MAP_SHARED, 写操作会写回映射的文件
 MAP_PRIVATE, 写操作不会写回映射文件
 以上两个参数二选一, 通常使用 MAP_SHARED
 MAP_ANONYMOUS, 映射物理内存时使用该参数, 该参数会导致忽略后续两个参数 fd, offset, 映射文件时不使用
fd : 文件描述符, 要映射的文件
offset : 文件偏移位置, 从文件的哪个偏移位置开始映射
返回值 : 映射之后的首地址, 失败返回-1

注意:

- mmap 时, offset+size < 文件的大小

- open 文件时候的权限 >= mmap 时的权限

总结: mmap 映射文件成功, 使得文件中被映射区域的每一个字节都对应一个虚拟地址, 映射成功后读写文件就和操作内存一样

(2) munmap函数 : 解除文件映射

int munmap(void *addr, size_t length)
addr : 要解除映射的首地址
size : 要接触映射的长度, 通常和 mmap 保持一直就可以了

3.8 目录操作

typedef struct __dirstream 
{ 
 void *__fd; 
 char *__data; 
 int __entry_data; 
 char *__ptr; 
 int __entry_ptr; 
 size_t __allocation; 
 size_t __size; 
 __libc_lock_define (, __lock) 
}DIR;

(1) opendir函数 : 打开一个文件目录

DIR *opendir(const char *name)

(2) readdir函数 : 读取文件目录信息

struct dirent
{
 ino_t d_ino; //d_ino 此目录进入点的inode
 ff_t d_off; //d_off 目录文件开头至此目录进入点的位移
 signed short int d_reclen; //d_reclen _name 的长度, 不包含NULL 字符
 unsigned char d_type; //d_type d_name 所指的文件类型 d_name 文件名
 har d_name[256];
};
struct dirent *readdir(DIR *dir)

(3) closedir函数 : 关闭文件目录

int closedir(DIR *dir)

使用步骤:

1) opendir(), 返回目录指针(DIR*)

2) 使用目录指针来循环调用 readdir

逐一读取每个子项, 返回值是一个结构提指针, 结构提如下

struct dirent

{

d_type; //文件类型

d_name; //文件名称

...

}

3) closedir 关闭目录

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言