fopen,fwrite,fread,fseek,fclose这些函数都是库函数,是c库当中提供能给程序员调用的函数。
函数描述:
path:待打开的文件(文件路径+文件名称)
mode:以何种方式打开
返回值:打开成功返回文件流指针,打开失败返回NULL。
示例:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
//以只读方式打开文件linux
FILE *fp = fopen("./linux","r"); // 不管是r还是r+,如果文件不存在都会打开失败
if(!fp)
{
perror("fopen");
return -1;
}
printf("open success\n");
return 0;
}
//输出结果:
fopen: No such file or directory
创建linux文件,再次以只读方式打开,结果如下:
[test@localhost c_file]$ touch linux
[test@localhost c_file]$ ./test_file
open success
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
FILE *fp = fopen("./linux","w"); //不管是w还是w+,如果文件不存在都会创建文件
//如果存在,则清空文件
if(!fp)
{
perror("fopen");
return -1;
}
printf("open success\n");
return 0;
}
//输出结果:
open success
此时查看文件:
[test@localhost c_file]$ make
gcc test.c -o test_file
[test@localhost c_file]$ ./test_file
open success
[test@localhost c_file]$ ls
linux makefile test.c test_file
现在linux文件存在,往这个文件中随便写入数据,然后再次以只写方式打开文件:
[test@localhost c_file]$ cat linux
Hello World
[test@localhost c_file]$ ./test_file
open success
[test@localhost c_file]$ cat linux
[test@localhost c_file]$ #文件内容已经被清空
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
FILE *fp = fopen("./linux","a"); //不管是a还是a+,如果文件不存在都会创建文件
//如果存在,当前文件流指针指向文件末尾,并不会清空文件内容
if(!fp)
{
perror("fopen");
return -1;
}
printf("open success\n");
return 0;
}
//输出结果:
open success
现在linux文件存在,往这个文件中随便写入数据,然后再次以追加方式打开文件:
[test@localhost c_file]$ echo "Hello world" >> linux
[test@localhost c_file]$ cat linux
Hello world
[test@localhost c_file]$ ./test_file
open success
[test@localhost c_file]$ cat linux
Hello world #可以看到文件内容没有被清空
函数描述:
ptr:要往文件当中写的内容
size:写入块的大小,单位是字节
nmemb:块的个数,单位是个(写入文件字节的数量:size * nmemb)
注意:一般在程序中使用时,是将size设置为1,则nmemb就表示写入的字节数量。
stream:文件流指针
返回值:返回写入成功块的个数,切记不是写入成功字节的数量。
示例:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
int main()
{
FILE *fp = fopen("./linux","w+"); //以读写方式打开文件
if(!fp)
{
perror("fopen");
return -1;
}
printf("open success\n");
//创建buf数组用于保存需要往文件写入的数据
char buf[1024] = {0};
const char *ptr = "Hello World!";
strncpy(buf,ptr,strlen(ptr));
size_t ret = fwrite(buf,1,strlen(ptr),fp);
printf("ret:%d\n",ret); // 返回的是写入成功块的个数
return 0;
}
输出结果:
[test@localhost c_file]$ ./test_file
open success
ret:12
[test@localhost c_file]$ cat linux
Hello World![test@localhost c_file]$
函数描述:
ptr:要将读到的内容保存在哪里
size:每次读块的大小
nmemb:块的个数
stream:文件流指针
返回值:成功读到的块的个数,返回0说明读取成功了但是没有读到内容。
示例:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
int main()
{
FILE *fp = fopen("./linux","r");
if(!fp)
{
perror("fopen");
return -1;
}
printf("open success\n");
// 创建数组用以保存读取的数据
char buf[1024] = {0};
size_t ret = fread(buf,1,sizeof(buf)-1,fp);
printf("buf:%s\n",buf);
printf("ret:%d\n",ret); // 返回的是读到的块的个数
return 0;
}
输出结果:
[test@localhost c_file]$ ./test_file
open success
buf:Hello world
ret:12
函数描述:
stream:文件流指针
offset:偏移量
whence:
示例:
在一个程序中在文件写入数据后,想要继续读取数据,此时就用到了fseek函数
不使用fseek:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
int main()
{
FILE *fp = fopen("./linux","w+");
if(!fp)
{
perror("fopen");
return -1;
}
printf("open success\n");
char buf_w[1024] = {0};
const char *ptr = "Hello World!";
strncpy(buf_w,ptr,strlen(ptr));
size_t ret_w = fwrite(buf_w,1,strlen(ptr),fp);
printf("ret_w:%d\n",ret_w);
//fseek(fp,0,SEEK_SET); //将文件流指针偏亮到文件头,偏移量为0
char buf_r[1024] = {0};
size_t ret_r = fread(buf_r,1,sizeof(buf_r)-1,fp);
printf("buf_r:%s\n",buf_r);
printf("ret_r:%d\n",ret_r);
return 0;
}
输出结果:
[test@localhost c_file]$ ./test_file
open success
ret_w:12
buf_r: #此时文件流指针指在文件末尾,所以没有读取到
ret_r:0 # 返回值为-1,表示fread函数调用错误,为0,则表示读取成功了,但是没有读到内容
使用fseek后:
[test@localhost c_file]$ ./test_file
open success
ret_w:12
buf_r:Hello World!
ret_r:12
[test@localhost c_file]$ cat linux
Hello World![test@localhost c_file]$
关闭文件流指针
fclose(fp); // fp 文件流指针
—— 系统调用函数的操作文件接口
open,write,read,lseek,close这些函数都是系统调用,是操作系统内核为程序员提供的函数
函数描述:
pathname:要打开的文件名称(路径+名称)
flags:以何种方式打开
必须的宏,三个宏有且只能出现一个
可选的宏
使用方式:必须的宏和可选的宏之间使用按位或的方式(部分)
例:O_RDWR | O_CREAT (是按照位图的方式来使用的)
mode:权限,给新创建出来的文件设置权限,传参的时候,传八进制数字就可以了。
返回值:打开成功,返回大于等于0的数字,是文件描述符,打开失败,返回-1。
示例:
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int fd = open("./linux",O_RDWR | O_CREAT,0664);
if(fd<0)
{
perror("open");
return -1;
}
printf("open success\n");
printf("fd:%d\n",fd);
return 0;
}
输出结果:
[test@localhost sys_file]$ ./sys_file
open success
fd:3
[test@localhost sys_file]$ ls
linux makefile sys_file test.c
函数描述:
fd:文件描述符,open的返回值
buf:往文件里写的内容
count:写的内容的大小
返回值:写成功的字节数量
示例:
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int fd = open("./linux",O_RDWR | O_CREAT,0664);//以读写方式打开文件,如果文件不存在,则创建
if(fd<0)
{
perror("open");
return -1;
}
printf("open success\n");
printf("fd:%d\n",fd);
char buf[1024] = {0};
const char *ptr = "Hello World!";
strncpy(buf,ptr,strlen(ptr));
write(fd,buf,strlen(ptr));
return 0;
}
输出结果:
[test@localhost sys_file]$ ./sys_file
open success
fd:3
[test@localhost sys_file]$ cat linux
Hello World![test@localhost sys_file]$
函数描述:
fd:文件描述符,open的返回值
buf:要将读到的内容放到哪里去
count:最大可以读多少个单位字节
返回值:返回读到的字节数量,返回0说明读取成功了,但是没有读取到内容
示例:
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int fd = open("./linux",O_RDWR | O_CREAT,0664);
if(fd<0)
{
perror("open");
return -1;
}
printf("open success\n");
printf("fd:%d\n",fd);
char buf[1024] = {0};
read(fd,buf,sizeof(buf)-1); //-1 是为了给 '\0'留一个位置
printf("buf:%s\n",buf);
return 0;
}
输出结果:
[test@localhost sys_file]$ ./sys_file
open success
fd:3
buf:Hello World!
函数描述:
fd:文件描述符
offset:偏移量
whence:
示例:
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
int main()
{
//打开文件
int fd = open("./linux",O_RDWR | O_CREAT,0664);
if(fd<0)
{
perror("open");
return -1;
}
printf("open success\n");
printf("fd:%d\n",fd);
//写
char buf_w[1024] = {0};
const char *ptr = "Hello World!";
strncpy(buf_w,ptr,strlen(ptr));
write(fd,buf_w,strlen(ptr));
//lseek(fd,0,SEEK_SET); //将文件流指针偏移到文件头
//读
char buf_r[1024] = {0};
read(fd,buf_r,sizeof(buf_r)-1); //-1 是为了给 '\0'留一个位置
printf("buf_r:%s\n",buf_r);
return 0;
}
不使用lseek输出结果:
[test@localhost sys_file]$ ./sys_file
open success
fd:3
buf_r: #此时文件流指针指在文件末尾,所以没有读取到
使用lseek之后:
[test@localhost sys_file]$ ./sys_file
open success
fd:3
buf_r:Hello World!
关闭文件描述符
close(fd); //fd 文件描述符
close(0); // 关闭标准输入
close(1); // 关闭标准输出
close(2); // 关闭标准错误
通过对open函数的学习与理解,文件描述符fd就是一个整数。
操作系统会为每一个进程在磁盘上创建一个以进程号命名的文件夹,在该文件夹下有一个fd文件夹,保存的信息即为该进程打开的文件描述符信息。
下面来一段代码演示:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
int fd = open("./linux",O_RDWR | O_CREAT,0644);//打开文件
if(fd<0)
{
perror("open");
return -1;
}
printf("fd:%d\n",fd);
while(1)
{
sleep(1);
}
return 0;
}
//输出结果
fd:3 //然后程序死循环,方便查看信息
查看该进程的文件描述符信息:
可以看到,当我们新创建出来一个进程,势必会打开3个文件描述符,分别对应,标准输入 (0),标准输出 (1),标准错误 (2)。
如图所示,当 ./main运行该程序时:
可以看到,文件描述符其实就是在内核当中的fd_array数组的下标。
通过上面的代码发现,打开新的文件后,fd的值为3,那么我们关闭0或者2再看
示例代码:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
close(0);
int fd = open("./linux",O_RDWR | O_CREAT,0644);//打开文件
if(fd<0)
{
perror("open");
return -1;
}
printf("fd:%d\n",fd);
while(1)
{
sleep(1);
}
return 0;
}
//输出结果:
fd:0 //然后程序死循环,方便查看信息
如图所示:关闭0以后
如图所示:关闭2以后
结论:文件描述符的分配规则:在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符即最小未占用原则。
如图所示:
区别:
当我们打开一个文件,操作系统会给程序分配一个文件描述符,如果在使用完毕之后,没有及时关闭文件,就会造成文件句柄泄露。
命令行查看:
可以使用ulimit -[选项][值] 修改对应内容,比如打开文件最大数量。
代码查看:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
int fd_count=0;
while(1)
{
int fd = open("./linux",O_RDWR | O_CREAT,0664); // 一直打开文件
if(fd<0)
{
perror("open");
break;
}
printf("fd:%d\n",fd);
fd_count++;
}
printf("fd_count:%d\n",fd_count);
return 0;
}
输出结果:
[test@localhost fd]$ ./fd_count
fd:3
fd:4
fd:5
fd:6
fd:7
……
fd:1019
fd:1020
fd:1021
fd:1022
fd:1023
open: Too many open files #到1024就停下来了
fd_count:1021 #从文件描述符3开始到1023
[test@localhost fd]$
由结果可得知:fd从3开始是因为新创建出来一个进程,操作系统势必会打开3个文件描述符,即 0(标准输入)、1(标准输出)、2(标准错误)
[test@localhost dup]$ echo "Hello" > linux #将Hello重定向到linux文件中
[test@localhost dup]$ cat linux
Hello
[test@localhost dup]$ echo "linux" > linux #清空linux文件内容,再把linux重定向到linux文件中
[test@localhost dup]$ cat linux
linux
[test@localhost dup]$
[test@localhost dup]$ echo "Hello" >> linux
[test@localhost dup]$ cat linux
linux
Hello
[test@localhost dup]$ #并没有清空文件内容而是追加在后面
重定向的本质如图所示:
流程:
代码演示:
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
//打开文件,不存在则创建
int fd = open("./linux",O_CREAT | O_RDWR,0664);
if(fd<0)
{
perror("open");
}
printf("fd:%d\n",fd);
//将标准输出重定向到文件当中
//dup2(int oldfd,int newfd)
//oldfd --> fd(上面打开文件的文件描述符) newfd --> 1(标准输出)
// dup2(fd,1);
int ret_d = dup2(fd,1);
printf("ret_d:%d\n",ret_d);//返回的是1这个文件描述符
//成功以后,下面的代码在往标准输出当中进行输出的时候,就是往文件当中写了
printf("Hello World\n");
// close(fd);
while(1)
{
sleep(1);
}
return 0;
}
//输出结果:
fd:3 //之后陷入死循环,为了方便查看文件描述信息
可以发现已经将标准输出重定向到了文件当中,验证一下是否打印到了文件当中
[test@localhost dup]$ cat linux
ret_d:1
Hello World #可以看到dup2函数之后的两条打印语句都打印到了linux这个文件中
ajax (ajax开发) AJAX即“Asynchronous Javascript And XML”(异步JavaScript...
VBScript数据类型 VBScript只有一种数据类型,即Variant,称为变体型。Varriant...
文章目录 一、什么是Linux 二、什么是shell 三、shell行提示符的含义 1. shell类...
简要说明 最近写了一下vue控制权限(菜单、路由)的项目,用了vuex、addRoutes动态...
最近使用React Hooks结合 zarm 组件库,基于js对象配置方式开发了大量的h5表单页...
首先来解释一下什么叫做运算符 对变量或常量进行操作的符号叫做运算符 组合起来...
前言 在项目开发中常常会需要做发送 Email 的功能,在 ASP.NET Core 中你可以用 ...
本文实例讲述了thinkphp3.2.3框架动态切换多数据库的方法。分享给大家供大家参考...
文章目录 关系数据库 关系数据库简介 关系数据结构及形式化定义 关系 关系模式 ...
所有的语言开篇都是Hello Word,数据处理引擎也有Hello Word。那就是Word Count。...