C语言文件操作相关接口
1.fopen
其中第一个参数 path 为文件路径,第二个参数mode 为打开文件后对文件进行操作的类型,通常mode 有以下几种参数。
- r 只读
- r+ 读写(会清空原文件的内容)
- w 只写(会清空原文件的内容,如果没有则先创建)
- w+ 读写(如果文件不存在,则先创建文件再进行操作,会清空原文件的内容)
- a 追加(在原文件内容后面追加新内容)
- a+ 追加(如果文件不存在,则先创建文件再进行操作,在原文件内容后面追加新内容)
在打开文件时会返回一个FILE *类型的文件描述符,可以看作是一个整数,这个文件描述符一般是从3开始,因为0,1,2都被占用,而0,1,2分别为标准输入,标准输出,标准错误。 后面会对文件描述符进行详细介绍。
2.fclose
对文件进行操作结束的时候需要关闭文件描述符(fp)。
3.fread/fwrite
其中fread/fwrite的四个参数相同。
- ptr 为所要操作的数据地址
- size 为读取或写入的方式,以字节大小为单位(可以选择按照4个字节或者其他字节数来读取)
- nmemb 为读取的元素个数(如以4个字节读取4个元素)
- stream 你要读写到那个文件的文件描述符
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp = fopen("myfile", "w");
//以写的方式打开文件,"myfile" 未加路径则表示打开当前目录下的"myfile"文件
if (!fp)
{
printf("fopen error!\n");
}
const char *msg = "hello world!\n";
int count = 5;
while (count--)
{
fwrite(msg, strlen(msg), 1, fp);
//将msg的内容写入文件中,以整个msg的字符串长度字节数为单位,写入一个元素
}
fclose(fp);
return 0;
}
系统调用接口
1.概念
顾名思义 系统调用接口就是操作系统提供的接口,操作系统提供是文件操作相关的接口如:read、write、open、close、lseek等,而上述提到的c语言中的文件操作函数实际来自c语言的库函数,是c语言对系统调用接口进行的封装。如下图可看到系统调用接口在c lib库下面。
2.接口介绍
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);
//pathname: 要打开或创建的目标文件
//flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。
参数:
//O_RDONLY: 只读打开
//O_WRONLY: 只写打开
//O_RDWR : 读,写打开
//这三个常量,必须指定一个且只能指定一个
//O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
//O_APPEND: 追加写
//返回值:
//成功:新打开的文件描述符
//失败:-1
//mode 选项只当使用O_DREAT时才使用
write
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
DESCRIPTION
write() writes up to count bytes from the buffer pointed
buf to the file referred to by the filedescriptor fd.
//fd 文件描述符
//buf 存放写入数据的缓冲区
//count 要从缓冲区写入文件的字节数
//返回值
//大于0:表示成功写入的字节数,即实际写入的数据大小。
//等于0:通常表示没有写入任何数据,可能是由于目标文件描述符已经被关闭。
//小于0:表示写入出错,此时返回值可能是以下几种错误码之一:
read
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
DESCRIPTION
read() attempts to read up to count bytes from file descriptor
fd into the buffer starting at buf.
//fd 文件描述符
//buf 存放写入数据的缓冲区
//count 从文件中读取内容的字节数
//返回值
//大于0:表示成功读取的字节数,即读取到的实际数据的大小。
//等于0:表示已经到达文件末尾(EOF),即没有更多的数据可读取。
//小于0:表示读取出错,此时返回值可能是以下几种错误码之一:
close
文件操作结束后需要关闭文件描述符
文件描述符fd
1.概念
每一个进程都有一个task_struct结构体 用来描述进程的各种内容,其中就有一个*file指向一张file_struct的结构表 该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件。文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。
2.文件描述符的分配规则
Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2.
0,1,2对应的物理设备一般是:键盘,显示器,显示器.
在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd = open("myfile", O_RDONLY);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n", fd);
close(fd);
return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
close(0);
int fd = open("myfile", O_RDONLY);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n", fd);
close(fd);
return 0;
}
3.输入输出重定向的底层逻辑
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
close(1);
int fd = open("myfile", O_WRONLY|O_CREAT, 00644);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n", fd);
fflush(stdout);
close(fd);
exit(0);
}
此时,我们发现,本来应该输出到显示器上的内容,输出到了文件myfile 当中,其中,fd=1。这种现象叫做输出重定向.
使用dup2 系统调用
意思就是将原本要输出的新的文件描述符的内容输出到旧的文件描述符中。
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
int fd = open("./log", O_CREAT | O_RDWR);
if (fd < 0)
{
perror("open");
return 1;
}
close(1);
//将标准输出的内容输出到log中
dup2(fd, 1);
for (;;)
{
char buf[16] = {0};
ssize_t read_size = read(0, buf, sizeof(buf) - 1);
if (read_size < 0)
{
perror("read");
break;
}
printf("%s", buf);
fflush(stdout);
}
return 0;
}