一、文件打开与关闭函数
(一)open函数
所需头文件:#include <sys/types.h>、#include <sys/stat.h>、#include <fcntl.h>
原型:int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
用文件IO的方式打开文件
参数:
pathname文件路径和名字不写路径默认打开当前路径下的文件;
flags打开文件的方式:
- O_RDONLY:以只读方式打开文件,文件不存在则打开失败,将光标定位到开头
- O_WRONLY:以只写方式打开文件,文件不存在则打开失败,将光标定位到开头
- O_RDWR:以读写方式打开文件,文件不存在则打开失败
- O_APPEND:以追加方式打开文件,文件不存在则打开失败
- O_CREAT:文件不存在则创建文件;如果flags中填写了O_CREAT,就必须填写第三个参数,第三个参数代表创建文件的权限。
- O_TRUNC如果文件存在就清空;
- O_EXCL:结合O_CREAT使用,如果文件不存在会创建文件;如果文件存在会报错,错误码为EEXIST

mode创建文件的权限,一般用8进制表示;实际创建出来的文件权限 = (mode & ~umask)
umask:文件的掩码,通过umask命令可以查看掩码的默认值是0002

~umask:文件掩码的取反是在最大文件的权限的基础上进行取反,最大文件的权限是0666(文件没有执行权限,所以可读可写:4+2=6);实际创建出来的文件权限 = (0666 & ~(0002)) = (0666 & 0664) = 0664。目录的最大权限0777(有可执行权限6+1=7)。

返回值:成功则返回文件描述符;失败则返回-1,错误码errno会被正确设置。
(二)close函数
所需头文件:#include <unistd.h>
原型:int close(int fd); 用文件IO的方式关闭文件
参数:fd文件描述符
返回值:成功则返回0;失败则返回-1,错误码errno会被正确设置。
#include <stdio.h>
//open函数所需头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//close所需头文件
#include <unistd.h>
//errno所需头文件
#include <errno.h>
int main(int argc,const char* argv[])
{
//第一个参数(文件):如果不写路径默认当前路径下的文件
//第二个参数(打开文件方式):只读(O_RDONLY),若不存在则创建(O_CREAT)新文件
//一旦创建新文件,则需要使用第三个参数,默认权限0666
//如果文件不存在则创建文件,如果文件存在则报错
int fd=0;//文件描述符(从3开始)
fd=open("test.c",O_RDONLY|O_CREAT|O_EXCL,0666);
if(fd == -1){
//如果文件打开失败(前面有参数O_EXCL:不存在则创建,存在则报错)则错误码errno会重新设置
if(errno == EEXIST){
printf("文件已存在\n");
}
perror("文件打开失败");
return -1;
}
printf("文件打开成功\n");
printf("文件描述符fd=%d\n",fd);
//使用open函数时要关闭文件(关闭文件描述符)
//如果关闭文件成功,返回值0;关闭失败,返回值1
int ret=0;
ret=close(fd);
if(ret == -1){
perror("关闭文件失败");
return -1;
}
printf("关闭文件成功,ret=%d\n",ret);
return 0;
}
二、文件读写函数
(一)read函数
所需头文件:#include <unistd.h>
原型:ssize_t read(int fd, void *buf, size_t count); 用文件IO的方式读取文件中的内容
参数:fd文件描述符;buf存储读取到的数据的首地址;count想要读取的字节的个数
返回值:成功则返回读取到的字节的个数;返回0表示读取到文件的结尾。失败则返回-1,错误码errno会被正确设置。
//从文件中读取数据
char buf[1024]={0};
ssize_t ret_read=0;
//成功则返回读取到的数据总个数
//如果read返回0,则读取到了文件的末尾
//如果想要读取字节数超过了实际文件数据字节数,则read返回实际读取到的字节数
ret_read=read(fd,buf,sizeof(buf));
if(ret_read==-1){
perror("文件读取失败");
return -1;
}
printf("文件读取成功,ret_read=%ld\n",ret_read);
printf("读取到的数据是:%s\n",buf);
(二)write函数
所需头文件:#include <unistd.h>
原型:ssize_t write(int fd, const void *buf, size_t count); 用文件IO的方式往文件中写入内容
参数:fd文件描述符;buf想要写入数据的首地址;count想要写入的字节的个数
返回值:成功则返回写入的字节的个数,返回0表示不会写任何的数据;失败则返回-1,错误码errno会被正确设置。
//向文件中写入数据
//向文件中写入一个整数
int value=100;
ssize_t ret_write=0;
ret_write=write(fd,&value,sizeof(value));
if(ret_write==-1){
perror("写入一个整数失败");
return -1;
}
printf("写入一个整数成功,ret_write=%ld\n",ret_write);
//写入字符串
char *str="hello";
ret_write=write(fd,str,strlen(str));
if(ret_write==-1){
perror("写入一个字符串失败");
return -1;
}
printf("写入一个字符串成功,ret_write=%ld\n",ret_write);
//写入一个结构体
struct Student stu={"lisa"};
ret_write=write(fd,&stu,sizeof(stu));
if(ret_write==-1){
perror("写入一个结构体失败");
return -1;
}
printf("写入一个结构体成功,ret_write=%ld\n",ret_write);
(三)read和write练习
实现文件的拷贝 cp 命令的功能

实现思路:对输入参数的参数个数进行检查;以只读方式打开源文件,以只写方式打开目标文件,并且判断文件是否打开成功;循环进行读取和写入;
代码完成拷贝后,需手动用diff命令验证两个文件中的内容是否相同;
#include <stdio.h>
//open函数所需头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//read,write,close所需头文件
#include <unistd.h>
int main(int argc,const char* argv[])
{
//检查参数个数
if(argc!=3){
printf("参数输入错误\n");
printf("Usage:./a.out src dst\n");
return -1;
}
//打开文件
int src_fd=0;//文件描述符(从3开始)
//O_RDONLY如果源文件 不存在则报错
if((src_fd=open(argv[1],O_RDONLY)) == -1){
perror("源文件打开失败");
return -1;
}
printf("源文件打开成功\n");
printf("源文件描述符src_fd=%d\n",src_fd);
int dst_fd=0;//文件描述符(从3开始)
//O_WRONLY如果目标文件 不存在则报错
//以只写的方式打开目标文件,如果文件不存在则创建(O_CREAT)文件,如果文件存在则清空(O_TRUNC)写入
if((dst_fd=open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0666)) == -1){
perror("目标文件打开失败");
return -1;
}
printf("目标文件打开成功\n");
printf("目标文件描述符dst_fd=%d\n",dst_fd);
//循环读取与写入
char buf[1024]={0};
ssize_t ret_read=0;//用于接收read返回值
ssize_t ret_write=0;//用于接收write返回值
while((ret_read=read(src_fd,buf,sizeof(buf)))>0){
ret_write=write(dst_fd,buf,ret_read);
if(ret_write==-1){
perror("写入目标文件失败");
return -1;
}
if(ret_read!=ret_write){
printf("写入的字节数与读取的字节数不一致");
return -1;
}
}
//关闭文件
close(src_fd);
close(dst_fd);
return 0;
}
三、文件定位与控制函数
(一)lseek函数
所需头文件:#include <sys/types.h>、#include <unistd.h>
原型:off_t lseek(int fd, off_t offset, int whence); 定位光标的位置(光标实际指文件偏移量)
参数:fd文件描述符;
offset偏移量:
- >0向后偏移;
- =0不偏移;
- <0向前移动
whence从哪个位置开始偏移
- SEEK_SET :从文件的开头
- SEEK_CUR:从当前位置
- SEEK_END:从文件的结尾
若文件以 O_APPEND 打开,write 会强制将偏移量置为文件末尾,lseek 调整的偏移量仅对 read 生效
返回值:成功则返回从文件开头计算出的结果偏移量(单位:字节);失败则返回-1,错误码errno会被正确设置。
//以读写和追加的方式打开文件
int fd=0;//文件描述符(从3开始)
if((fd=open("test.txt",O_RDWR|O_APPEND|O_CREAT,0666)) == -1){
perror("文件打开失败");
return -1;
}
printf("文件打开成功,文件描述符fd=%d\n",fd);
//从文件开头偏移2
off_t offset=0;
if(-1==(offset=lseek(fd,2,SEEK_SET))){
perror("文件定位失败");
return -1;
}
printf("文件定位成功,offset=%ld\n",offset);
//设置光标位置,读取文件数据
char buf[1024]={0};
if(read(fd,buf,sizeof(buf)) == -1){
perror("读取数据失败");
return -1;
}
printf("读取数据成功,buf=%s\n",buf);
//写入数据---会追加到文件的末尾
//虽然重新定位了光标位置,但如果以追加的方式打开文件,则会从末尾写入
char *p="HELLO WORLD";
if(write(fd,p,strlen(p))==-1){
perror("写入数据失败");
return -1;
}
printf("写入数据成功\n");
//关闭文件
close(fd);
(二)fcntl函数
所需头文件:#include <unistd.h>、#include <fcntl.h>
原型:int fcntl(int fd, int cmd, ... /* arg */ ); 对打开的文件描述符进行多种控制(如 复制文件描述符、设置和获取文件描述符标志、实现文件锁等等)
参数:fd文件描述符;
cmd指定要执行的控制操作命令:
- - F_DUPFD:复制描述符
- - F_GETFD:获取描述符标志
- - F_SETFL:设置文件状态标志(arg 是整数,如 O_NONBLOCK)
- - F_GETLK:获取锁信息(arg 是 struct flock *)
- - F_SETLK:尝试加锁(非阻塞,arg 是 struct flock *)
- - F_SETLKW:阻塞加锁(arg 是 struct flock *)
struct flock {
short l_type;//锁类型:F_RDLCK(读锁)、F_WRLCK(写锁)、F_UNLCK(解锁)
short l_whence;//锁的基准位置(同 lseek 的 whence:SEEK_SET/SEEK_CUR 等)
__kernel_off_t l_start;//锁的起始偏移量
__kernel_off_t l_len;//锁的长度(0 表示到文件末尾)
__kernel_pid_t l_pid;//持有锁的进程 ID(仅 F_GETLK 有效)
};
...可选参数,是否必填由 cmd 决定
返回值:
- - F_DUPFD:成功返回新描述符,失败返回 -1
- - F_GETFD/F_GETFL/F_GETLK:成功返回对应值,失败返回 -1
- - F_SETFD/F_SETFL/F_SETLK/F_SETLKW:成功返回 0,失败返回 -1
402




被折叠的 条评论
为什么被折叠?



