01-文件IO
1 | #include <sys/types.h> |
open/close
函数原型:
- 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_CREAT
- 创建文件时检测文件是否存在: O_EXCL
- 如果文件存在, 返回-1
- 必须与O_CREAT一起使用
追加文件: O_APPEND
文件截断: O_TRUNC
设置非阻塞: O_NONBLOCK
mode – 指定0777
八进制数
最终权限: mode & ~umaks
umask 0002
- 000000010
- ~
- 111111101
- 111111111
- &
- 111111101
- 775
read
函数原型: ssize_t read(int fd, void *buf, size_t count);
参数:
- fd – open的返回值
- buf - 缓冲区, 存放读取的数据
- count – 缓冲区的最大容量 sizeof(buf)
返回值:
- -1: 失败
- >0: 读出的字节数
- =0: 文件读完了
write
函数原型: ssize_t write(int fd, const void *buf, size_t count);
参数:
- fd: 文件描述符, open 返回值
- buf: 要往文件中写的数据
- count: 有效数据的长度
返回值:
- -1: 失败
- >0: 写入的字节数
lseek
函数原型: off_t lseek(int fd, off_t offset, int whence);
- SEEK_SET
- SEEK_CUR
- SEEK_END
使用:
- 文件指针移动到头部:
- lseek(fd, 0, SEEK_SET);
获取文件指针当前的位置:
- int len = lseek(fd, 0, SEEK_CUR);
获取文件长度:
- int len = lseek(fd, 0, SEEK_END);
文件拓展
- 文件原大小100k, 拓展为1100k
lseek(fd, 1000, SEE_END);
最后做一次写操作write(fd, “a”, 1);
阻塞和非阻塞
阻塞和非阻塞是文件的属性还是read函数的属性?
文件的属性
普通文件:hello.c
- 默认不阻塞
终端设备:/dev/tty
- 默认阻塞
- 管道
- 套接字
02-stat/lstat函数
获取文件属性
1 | #include <unistd.h> |
st_mode – 16位整数
0-2 bit – 其他人权限
- S_IROTH 00004 读权限
- S_IWOTH 00002 写权限
- S_IXOTH 00001 执行权限
- S_IRWXO 00007 掩码, 过滤 st_mode中除其他人权限以外的信息
- 3-5 bit – 所属组权限
- S_IRGRP 00040 读权限
- S_IWGRP 00020 写权限
- S_IXGRP 00010 执行权限
- S_IRWXG 00070 掩码, 过滤 st_mode中除所属组权限以外的信息
- 6-8 bit – 文件所有者权限
- S_IRUSR 00400 读权限
- S_IWUSR 00200 写权限
- S_IXUSR 00100 执行权限
- S_IRWXU 00700 掩码, 过滤 st_mode中除文件所有者权限以外的信息
- 12-15 bit – 文件类型
- S_IFSOCK 0140000 套接字
- S_IFLNK 0120000 符号链接(软链接)
- S_IFREG 0100000 普通文件
- S_IFBLK 0060000 块设备
- S_IFDIR 0040000 目录
- S_IFCHR 0020000 字符设备
- S_IFIFO 0010000 管道
- S_IFMT 0170000 掩码,过滤 st_mode中除文件类型以外的信息(st_mode & S_IFMT) == S_IFREG
int stat(const char path, struct stat buf);
int lstat(const char path, struct stat buf);
- lstat读取的链接文件本身的属性
stat读取的是连接文件指向的文件的属性
- 追踪,穿透
03-文件属性函数
测试当前用户指定文件是否具有某种属性
当前用户, 使用哪个用户调用这个函数, 这个用户就是当前用户
int access(const char *pathname, int mode);
- 参数:
- pathname: 文件名
- mode: 4种权限
- R_OK – 读
- W_OK – 写
- X_OK – 执行
- F_OK – 文件是否存在
- 参数:
- 返回值:
- 0 - 有某种权限, 或者文件存在
- 1 - 没有, 或文件不存在
修改文件权限
int chmod(const char *filename, int mode);
参数:
- filename: 文件名
- mode: 文件权限, 八进制数
修改文件所有者和所属组
int chown(const char *path, uid_t owner, gid_t group);
函数参数:
path – 文件路径
owner – 整形值, 用户ID
- /etc/passwd
group – ….., 组ID
- /etc/group
修改文件大小
int truncate(const char *path, off_t length);
参数:
- path – 文件名
- length – 文件的最终大小
- \1. 比原来小, 删掉后边的部分
- \2. 比原来大, 向后拓展
04-目录操作相关函数
- int rename(const char oldpath, const char newpath);
int chdir(const char *path);
- 参数: 切换的路径
char getcwd(char buf, size_t size);
返回值:
- 成功: 当前的工作目录
- 失败: NULL
参数:
- buf: 缓冲区, 存储当前的工作目录
- size: 缓冲区大小
int mkdir(const char *pathname, mode_t mode);
- 参数:
- pathname: 创建的目录名
- mode: 目录权限, 八进制的数, 实际权限: mode & ~umask
- 参数:
int rmdir(const char *pathname);
- 参数: 空目录的名字
05-目录遍历相关函数
打开一个目录
DIR opendir(const char name);
- 参数: 目录名
- 返回值: 指向目录的指针
FILE* fp = fopen()
fread(buf, len, len,fp);
读目录
1
2
3
4
5
6
7
8struct dirent
{
ino_t d_ino; // 此目录进入点的inode
ff_t d_off; // 目录文件开头至此目录进入点的位移
signed short int d_reclen; // d_name 的长度, 不包含NULL 字符
unsigned char d_type; // d_name 所指的文件类型
har d_name[256]; // 文件名
};
d_type
- DT_BLK - 块设备
- DT_CHR - 字符设备
- DT_DIR - 目录
- DT_LNK - 软连接
- DT_FIFO - 管道
- DT_REG - 普通文件
- DT_SOCK - 套接字
- DT_UNKNOWN - 未知
struct dirent readdir(DIR dirp);
- 参数: opendir的返回值
- 返回值: 目录项结构体
06-dup-dup2-fcntl
复制文件描述符
int dup(int oldfd);
oldfd - 要复制的文件描述符
返回值: 新的文件描述符
dup调用成功:
- 有两个文件描述符指向同一个文件
返回值: 取最小的且没被占用的文件描述符
int dup2(int oldfd, int newfd);
oldfd -》hello
newfd -》world
假设newfd已经指向了一个文件,首先断开close与那个文件的链接,newfd指向oldfd指向的文件
- 文件描述符重定向
- oldfd和newfd指向同一个文件
- newfd没有被占用,newfd指向oldfd指向的文件
改变已经打开的文件的属性: fcntl
变参函数
复制一个已有的文件描述符
1 | int ret = fcntl(fd, F_DUPFD); |
获取/设置文件状态标志
- open 的flags参数
- 获取文件状态标识
1 | int flag = fcntl(fd, F_GETFL) |
- 设置文件状态标识
- flag = flag | O_APPEND;
fcntl(fd, F_SETFL, flag)
可以更改的几个标识: O_APPEND、O_NONBLOCK (常用)