Linux:基础IO——复习C语言文件IO相关操作
1.C语言操作文件接口
(1) fopen函数
函数原型:
FILE *fopen(const char *path,const char *mode);
参数解释:
path:待打开的文件(文件路径 + 文件名称)
mode:以何种方式打开
返回值:打开文件成功返回文件流指针,打开失败返回NULL
打开方式:
打开方式 | 解释 |
---|---|
r | 以只读方式打开,当文件不存在的时候,就会打开失败 |
r+ | 以读写方式打开,当文件不存在的时候,就会打开失败 |
w | 以只写方式打开。如果文件不存在,则会创建文件,如果文件存在则会截断(清空)文件 |
w+ | 以读写方式打开文件,如果文件不存在,则创建文件;如果文件存在,则会截断(清空)文件 |
a | 以追加方式打开,仅支持写,如果文件不存在,则会创建文件;当前的文件流指针指向了文件的末尾 |
a+ | 以追加方式打开,支持读写,如果文件不存在,则创建文件,当前文件流指针指向了文件的末尾 |
(2)fwrite函数
函数原型:
size_t fwrite(const void *ptr,size_t size,size_t nmemb,FILE *stream);
参数解释:
ptr:要往文件中写的内容
size: 写入块的大小,单位是字节
nmemb:块的个数,单位是个
stream:文件流指针
返回值:返回写入成功时块的个数(不是写入成功字节的数量)
注意:一般在程序中使用的时候,是将size设置成1,则nmembj就表示写入的字节数量
(3) fread函数
函数原型:
size_t fread(void *ptr,size_t size,size_t nmemb,FILE *stream);
参数解释:
ptr:要将读到的内容保存到哪里
size: 每次读块的大小
nmemb: 块的个数
stream:文件流指针
返回值:成功读到的块的个数
(4)fseek函数
函数原型:
int fseek(FILE *stream, long offset,int whence);
stream:文件流指针
offset:偏移量
whence:
SEEK_SET:文件流指针偏移到文件头部
SEEK_CUR:文件流指针偏移到当前位置
SEEK_END:文件流指针指向文件末尾位置
(5)fclose函数
函数原型:
int fclose(FILE *fp);
作用:关闭文件流指针
代码:
#include <stdio.h>
#include <string.h>
int main()
{
FILE* fp = fopen("./linux", "r+");
if(!fp)
{
perror("fopen");
return -1;
}
char buf[1024] = {0};
strcpy(buf, "linux-57");
ssize_t w_ret = fwrite(buf, 1, 9, fp);
printf("w_ret:%d\n", w_ret);
fseek(fp, 0, SEEK_SET);
memset(buf, '\0', sizeof(buf));
ssize_t r_ret = fread(buf, 1, sizeof(buf) - 1, fp);
printf("r_ret:%d, --- %s\n", r_ret, buf);
printf("open success\n");
return 0;
}
以上这些函数都是库函数,时C库中提供给程序员调用的函数,接下来再给大家分享一下操纵系统内核为程序员提供的函数。
2.系统调用函数的操作文件接口
(1)open函数
函数原型:
int open(const char *pathname, int flags, mod_t mode);
参数解释:
pathname:要打开的文件名称(路径+名称)
flags: 以何种方式打开
mode: 权限
返回值:打开成功,返回大于等于0的数字,是文件描述符,打开失败返回-1
flags处传递的参数为宏定义,分为必须的宏和可选的宏两种:
必须的宏:
名称 | 解释 |
---|---|
O_RDONLY | 只读方式 |
O_WRONLY | 只写方式 |
O_RDWR | 读写方式 |
可选的宏:
名称 | 解释 |
---|---|
O_APPEND | 追加 |
O_TRUNC | 截断 |
O_CREAT | 文件不存在则创建 |
使用的时候,用必须的宏和可选的宏组合使用,必须的宏和可选的宏之间使用按位或的方式。
例如:
O_RDWR | O_CREAT
(2)read函数
函数原型:
ssize_t read(int fd, void *buf,size_t count);
参数解释:
fd:文件描述符,open的返回值
buf:要将读到的内容放到那里去
count: 最大可以读多少个,单位字节
返回值: 返回读到的字节数量
(3)write函数
函数原型:
ssize_t read(int fd, const void *buf,size_t count);
参数解释:
fd:文件描述符,open的返回值
buf:往文件中写的内容
count: 写的内容的大小
返回值: 写成功的字节数量
(4)lseek函数
函数原型:
off_t lseek(int fd, off_t offset,int whence);
参数解释:
fd:文件描述符,open的返回值
offset:偏移量
whence:
SEEK_SET
SEEK_CUR
SEEK_END
(5)close
函数原型:
int close(int fd);
作用:关闭文件描述符
代码:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
close(0);
int fd = open("./linux", O_RDWR | O_CREAT, 0664);
if(fd < 0)
{
perror("open");
return -1;
}
printf("%d\n", O_RDWR | O_CREAT);
printf("fd : %d\n", fd);
while(1)
{
sleep(1);
}
return 0;
}
文件描述符
概念:文件描述符其实就是从0开始的小整数,当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。而open执行系统调用,所以必须将进程和文件关联起来。每个进程都有一个指针*files,指向一张表files_struct,该表最重要的部分就是包含一个指指针数组,每个元素都是一个指向打开文件的指针。所以,本质上,文件描述符就是该数组的下标,所以,只要拿着文件描述符,就可以找到对应的文件。
文件描述符的分配规则
首先我们来看下面的代码的结果
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.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;
}
运行结果:
结果为fd:3
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
close(0);
//close(2);
int fd = open("myfile", O_RDONLY);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n", fd);
close(fd);
return 0;
}
运行结果:
关闭2或者0,发现结果为fd:0
可以得出,文件描述符的分配规则为:在file_struct数组中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。
3.重定向
如果我们把1关闭了,就会看到这样的现象
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.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 <unistd.h>
int dup(int oldfd, int newfd);
例子:
#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);
dup2(fd, 1);
for (;;) {
char buf[1024] = {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;
}