目录
一、前言
二、相关API介绍
2.1 open
2.2 read
2.3 write
2.4 lseek
2.5 close
三、简单示例
3.1 示例1
3.2 示例2
一、前言
在 Linux 系统编程中,系统 I/O(又称低级 I/O)是直接通过操作系统提供的系统调用实现的文件操作接口。本文主要讲解open、read、write、lseek、close的功能以及用法。
二、相关API介绍
2.1 open
函数原型
int open(const char*pathname,int flags,mode_t mode);
函数功能:打开或创建文件,返回文件描述符。
参数说明
1.pathname
要打开或者创建的目标文件
2.flags
打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成falgs。
参数 | 作用 |
O_RDONLY | 只读(前三个三选一) |
O_WRONLY | 只写(前三个三选一) |
O_RDWR | 读写(前三个三选一) |
O_CREAT | 若文件不存在,则创建它,需要使用mode选项来指明新文件的访问权限 |
O_APPEND | 追加写入 |
O_TRUNC | 若文件存在则覆盖(清空文件内容) |
3.mode
新建文件时,要指明的文件访问权限。如果文件不存在且flags包含O_CREAT,mode参数决定新文件的权限;若文件已存在,mode会被忽略。未设置O_CREAT时,mode参数即使存在也不会被使用。
通过3位八进制数表示权限,每位对应“所有者-组-其他用户”的权限总和:
- 4:读(Read)
- 2:写(Write)
- 1:执行(Execute)
示例:
0644
:所有者读写(6=4+2),组和其他用户只读(4)。- 注意:数值前的
0
表示八进制格式,而非权限修饰符。
函数返回值
成功:新打开的文件描述符
失败:-1
open返回的文件描述符一定是最小的而且没有被使用的。
示例
int fd = open("test.txt", O_RDWR | O_CREAT, 0644);
注意点
- 实际权限 = mode & ~umask
umask
是进程的默认权限掩码(如0022
),用于屏蔽某些权限位。例如:若mode=0666(期望权限rw-rw-rw-),umask=0022,最终权限为0644(rw-r--r--) 。可通过umask(0)临时禁用掩码,强制使用mode的原始值 1。
- 即使创建文件时设置了权限(如0555禁止写),后续通过open返回的文件描述符仍可修改文件内容(权限检查仅在open时进行)。
- 权限的继承性:目录的权限影响其子文件的创建。若父目录无写权限,即使mode允许,也无法创建文件。
2.2 read
函数原型
ssize_t read(int fd, void * buf, size_t count);
函数功能:从文件描述符对应的文件中读取数据到缓冲区。
参数说明
- fd:文件描述符。
- buf:存储数据的缓冲区地址。
- count:期望读取的字节数。
函数返回值
成功:读到的字节数
已到达文件尾:0
失败:-1
示例
char buffer[1024];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer));
2.3 write
函数原型
ssize_t write (int fd, const void * buf, size_t count);
函数功能:将缓冲区数据写入文件描述符对应的文件。
参数说明
跟read类似
函数返回值
成功:已写入的字节数
失败:-1
示例
const char *data = "Hello, Linux!";
ssize_t bytes_written = write(fd, data, strlen(data));
2.4 lseek
函数原型
off_t lseek(int fd, off_t offset, int whence);
函数功能:调整文件读写指针的位置,支持随机访问。
参数说明
1.fd
文件描述符。
2.offset
偏移量,正前移,负后移。
3.whence
当前位置的基点
- SEEK_SET:文件的开头
- SEEK_CUR:文件指针的位置
- SEEK_END:文件结尾
函数返回值
成功:文件当前位移
失败:-1
示例
off_t new_pos = lseek(fd, 0, SEEK_END); // 移动到文件末尾
2.5 close
函数原型
int close(int fd)
函数功能:关闭文件描述符,释放系统资源。
参数说明
1.fd
需要关闭的文件描述符。
函数返回值
成功:返回0;
失败:返回-1,并设置errno
示例
close(fd);
注意点
程序结束时未关闭的文件可能导致资源泄漏,但内核会自动关闭。
三、简单示例
3.1 示例1
功能:写入一定数据,然后在读取这些数据。其中涉及到文件指针的问题,中间也涉及到关不关闭文件描述符。
/********************************************************************** 版权所有: Copyright (c) 2023-2024 XXX Company. All rights reserved.* 系统名称: * 文件名称: main.c* 内容摘要: open write lseek read close函数的应用* 当前版本: * 作 者: nebula嵌入式* 设计日期: 2023-01-21 15:58* 修改记录: * 日 期 版 本 修改人 修改摘要
**********************************************************************/
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include<unistd.h>int main(int argc, char *argv[])
{int fd, num;fd = open("a.txt", O_RDWR|O_CREAT|O_TRUNC, 0777);printf("fd=%d\n", fd);printf("hello world!!!\n");num = write(fd, "this is demo!", strlen("this is demo!"));if(num>0){printf("data is save!\n");}else{printf("data save failed!");}printf("num=%d\n", num);lseek(fd, -num, SEEK_CUR);int len;char str[50]="";len = read(fd, str, num);printf("len=%d\n", len);if(len>0){printf("txt content:%s\n", str);}else if(len<0){printf("content read failed!");}else{printf("read over!\n");}close(fd);return 0;
}
3.2 示例2
功能:指定路径拷贝文件。
/********************************************************************** 版权所有: Copyright (c) 2023-2024 XXX Company. All rights reserved.* 系统名称: * 文件名称: main.c* 内容摘要: 简单的文件拷贝程序* 当前版本: * 作 者: nebula嵌入式* 设计日期: 2025-03-01 15:11* 修改记录: * 日 期 版 本 修改人 修改摘要
**********************************************************************/
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include<unistd.h>int main(int argc, char *argv[])
{int source_fd = -1, des_fd = -1;int ret = 0, file_size = 0;char buf[1024] = {0};if (argc != 3) {printf("missing parameter!\n");printf("./program source_addr des_addr\n");return -1;}des_fd = open(argv[2], O_RDWR|O_CREAT|O_TRUNC, 0777);if(des_fd < 0){printf("open des fd failed!\n");close(des_fd);return -1;}source_fd = open(argv[1], O_RDONLY);if(source_fd < 0){printf("open source fd failed!\n");close(source_fd);return -1;}while((ret = read(source_fd, buf, sizeof(buf) - 1)) > 0){file_size += ret;if (write(des_fd, buf, ret) != ret) {perror("写入文件失败");break;}}if (ret < 0) {perror("读取文件失败");}printf("文件拷贝完成,共拷贝了 %d 字节\n", file_size);close(source_fd);close(des_fd);return 0;
}
./a.out cp_source_test.txt cp_des_test.txt