Linux系统文件操作函数
包含:open close read write lseek fcntl
是Linux底层提供的API,直接和系统内核交互:
- 无缓冲区
- 直接操作文件描述符
- 一切皆文件:普通文件、目录、设备、管道、socket都用这一套函数
! 说明
文件描述符
文件描述符是一个非负的整数,表示Linux内核打开的文件;
启动一个进程,默认打开三个文件描述符[0-2]
每次打开一个文件,系统分配一个最小的文件描述符;
内核里有一张表:进程 -> 文件描述符表 -> 指向文件结构体
需要包含的头文件:
c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> // open
#include <unistd.h> // read, write, close, lseek
#include <errno.h> // 错误码
6.1 open - 打开/创建文件
函数原型:
c
int open(const char *pathname, int flags, mode_t mode);
作用
打开或创建一个文件,返回 文件描述符 fd (小整数)。
flags(必须掌握)
O_RDONLY只读O_WRONLY只写O_RDWR读写O_CREAT文件不存在则创建O_TRUNC清空文件O_APPEND追加模式O_NONBLOCK非阻塞O_BINARY二进制(Linux 可省略)O_EXCL和 O_CREAT 一起用:文件存在则报错 (防止覆盖)
mode(创建文件时用,权限)
格式:0xxx 8 进制数字0644所有者读写,其他只读0755可执行文件
返回值- 成功:文件描述符 fd(>=0)
- 失败:
-1
示例:
c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> // open
#include <unistd.h> // read, write, close, lseek
#include <errno.h> // 错误码
int main()
{
// 以只写方式发开文件,不存在则创建,权限644
int fd = open("test.txt", O_WRONLY | O_CREAT, 0644);
// 判断是否成功,open失败返回-1
if(fd == -1){
perror("open:");
return -1;
}
// 关闭文件
close(fd);
return 0;
}
6.2 close - 关闭文件
关闭文件描述符,释放资源。
c
int close(int fd);
返回值
- 成功:0
- 失败:-1
6.3 write - 写文件
把 buf 中的数据写入文件。
c
ssize_t write(int fd, const void *buf, size_t count);
返回值
- 成功:实际写入字节数
- 失败:-1
示例:
c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> // open
#include <unistd.h> // read, write, close, lseek
#include <errno.h> // 错误码
#include <string.h>
int main()
{
int fd = open("test.txt", O_WRONLY | O_CREAT, 0644);
if(fd == -1){
perror("open:");
return -1;
}
// 写文件
char buff[] = "你好,C!";
// 返回写入的实际字节数
int ret = write(fd, buff, strlen(buff));
printf("write size = %d\n", ret);
close(fd);
return 0;
}
6.4 read - 读文件
从 fd 读取数据到缓冲区。
c
ssize_t read(int fd, void *buf, size_t count);
参数
fd:文件描述符
buf:存储读到的数据
count:期望读多少字节
返回值
-
0:实际读到的字节数
- =0:读到文件末尾(EOF)
- -1:出错
示例:
c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> // open
#include <unistd.h> // read, write, close, lseek
#include <errno.h> // 错误码
#include <string.h>
int main()
{
// 以只读方式打开文件
int fd = open("test.txt", O_RDONLY);
if(fd == -1){
perror("open:");
return -1;
}
// 读文件
char buff[1024] = {'\0'};
int ret = read(fd, buff, 1024);
printf("read size = %d, read info: %s\n", ret, buff);
close(fd);
return 0;
}
6.5 lseek - 移动文件的读写指针
定位文件读写位置(类似光标跳转)。
c
off_t lseek(int fd, off_t offset, int whence);
whence
- SEEK_SET 文件开始位置
- SEEK_CUR 当前位置
- SEEK_END 文件末尾
off_t offset 偏移量(正数向后,负数向前)
用途
- 获取文件大小:lseek(fd, 0, SEEK_END)
- 跳转到指定位置读写
返回值 - 成功:返回 新的光标位置(距离文件开头多少字节)
- 失败:返回 -1
用法: - 把光标移到 文件开头
c
lseek(fd, 0, SEEK_SET);
- 把光标移到 文件末尾
c
lseek(fd, 0, SEEK_END);
- 获取 文件大小(最经典用法)
c
off_t size = lseek(fd, 0, SEEK_END);
printf("文件大小:%ld 字节\n", size);
- 扩展文件大小(创建空洞文件)
c
// 把文件扩展到 1024 字节
lseek(fd, 1024, SEEK_SET);
write(fd, "a", 1); // 必须写一个字节才真正扩展
! 注意
- read /write 会自动让光标向后移动,读多少字节,光标自动后移多少;
- lseek 不会修改文件内容,只改光标位置;
- 光标可以移到文件末尾之外 → 形成空洞文件
- 管道、socket、终端设备 不能用 lseek(会报错)
示例:
c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> // open
#include <unistd.h> // read, write, close, lseek
#include <errno.h> // 错误码
#include <string.h>
int main()
{
int fd = open("test.txt", O_RDWR | O_CREAT, 0644);
if(fd == -1){
perror("open:");
return -1;
}
// 写文件
char buff[1024] = "Hello Rocky Linux!";
int ret = write(fd, buff, 1024);
// 写文件会移动文件指针,将文件指针移动带开始位置再读取
lseek(fd, 0, SEEK_SET);
memset(buff, 0, 1024);
// 读文件
ret = read(fd, buff, 1024);
printf("read size = %d, read info: %s\n", ret, buff);
close(fd);
return 0;
}