open函数的使用示例
利用open函数打开一个文件,并验证下是否能无限次打开文件
//openfile.c
#include <stdio.h> //C语言标准IO头文件,如调用printf()函数
#include <sys/types.h> //调用open()函数所需的头文件
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd; //定义一个变量fd,存放文件描述符
int i=1; //定义一个变量i,用来记录打开文件的次数
while(1)
{
fd = open("home/chenhai/test/main.c",O_RDWR); //打开main.c文件,以读写方式打开;在while循环中,连续的打开该文件
if(fd == -1)
{
printf("fail to open the file\n"); //如果文件描述符的值为-1,则打开文件失败
break;
}
else
{
printf("fd=%d,",fd);
printf("open main.c success %d\n",i++);
}
}
}
编译openfile.c程序并执行,按照程序逻辑,只要变量fd的值不为-1,就会陷入死循环一直打印
chenhai@linux:~/test$ gcc openfile.c -o demo
chenhai@linux:~/test$ ./demo
执行结果如下,可以看到,程序打印了1021次之后便退出了while循环,可见不能无限次打开文件main.c
通过Linux系统上的man手册,查看open函数的原型
chenhai@linux:~/test$ man 2 open //open函数属于内核提供的功能函数,所以在man手册的第2页
man手册是一个很好用的帮助文档,它分成9页:
页数 | 内容 |
---|---|
1 | Executable programs or shell commands 可执行程序或shell命令 |
2 | System calls (functions provided by the kernel) 系统调用(内核提供的功能) |
3 | Library calls (functions within program libraries) 库调用(程序库中的函数) |
4 | Special files (usually found in /dev) 个特殊文件(通常位于/ dev中) |
5 | File formats and conventions eg /etc/passwd 文件格式和约定,例如/ etc / passwd |
6 | Games |
7 | Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7) 杂项(包括宏包和惯例) |
8 | System administration commands (usually only for root) 系统管理命令(通常仅用于root) |
9 | Kernel routines [Non standard] 内核例程[非标准] |
截取man手册中的open函数部分介绍进行分析,对于系统提供的IO接口函数,我们不用去深究它的实现原理,我们只要使用它就好,可以看到该函数open的返回值类型是int,参数有两个,char型的指针*pathname指向的是需要打开的文件路径名,int型的变量flags是打开文件的操作权限请求
对man手册中关于open()函数的接口规范,总结如下表
那么上面的程序运行结果中,fd的值是从3开始的,前面的0 1 2去哪了呢?我们都知道,在Linux系统中有句话,“一切皆文件”,我们则可以使用系统IO接口去访问Linux系统中的所有文件,当申请打开一个文件的时候,系统会分配一个文件描述符给你,但是这个分配是有限度的,通过实验我们可以知道,打开文件的最大值为1023,其实就相当于去医院看病拿号一样,把医院当成一个系统,你去申请了排队看病,就分配了一个号码给你,当天的号码数量有限,分完即止,那每个人拿着这个号码(文件描述符),就可以去访问对应的医生(文件)了;之所以从3开始分配啊,是因为前面0-2都已经分配好了,0对应着标准输入设备文件(键盘),1对应着标准输出设备(屏幕),2标准出错设备(系统错误信息),所以啊这前面的三个号不能给你,你要申请只能从3开始
总结
每一个被打开的文件(键盘,显示器都是文件)都会有一个非负的描述符来对应他们;一个文件可以被重复打开多次,但不能无限次打开;每打开一次也都会有一个描述符对应,并且可以有不同的模式(文件操作权限);
write函数的使用示例
利用wirte函数,往一个空文本中写入数据
//创建一个空文本文件
chenhai@linux:~/test$ touch a.txt
//编写程序,将字符串"hello"写入a.txt writefile.c
#include <stdio.h>
#include <sys/types.h> //调用open()函数所需的头文件
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h> //调用wirte()函数所需的头文件
int main()
{
int fd;
char buf[20]={"hello"}; //定义一个20字节大小的数组(数据缓冲区),用于存放要写入的数据
//打开文件
fd = open("/home/chenhai/test/a.txt",O_RDWR); //读写方式打开,返回一个文件描述符,后面根据这个文件描述符对文件进行操作
if(fd == -1)
{
printf("open a.txt faild\n");
}
else
{
printf("open a.txt ok\n");
}
//写入数据
int ret = write(fd,buf,20); //将数据从缓冲区中写入fd指向的文件,共写入20字节
if(ret == -1)
{
printf("write a.txt faild\n");
}
else
{
printf("write a.txt ok\n");
}
return 0;
}
那么,我们同样可以通过man手册来查看一下write的使用原理
chenhai@linux:~/test$ man 2 write
NAME
write - write to a file descriptor
写入一个文件的描述符
SYNOPSIS
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数一: 需要写入的设备
参数二: 需要写入的数据缓存区
参数三: 需要写入的数据大小
返回值: 成功 返回值写入的字节数
失败 -1 错误
小于用户请求的字节数 写入失败
一般使用write 函数进行开发时,我们都是根据数据的真实大小写入。
注意:使用write 函数的时候,他会根据用户的需求数据写入,假设
真实数据不够,那么write 会自己补充一些乱码数据!!!!!
例子:
char buf[1024]={"hello"}; //真实数据为5个字节
write(fd,buf,1024); //最后写入的是1024个字节, 1024 - 5 (个无效数据)
read函数的使用示例
往一个文件写入数据,并读取数据
//readfile.c
#include <stdio.h>
#include <sys/types.h> //调用open()函数所需的头文件
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h> //write , read
int main()
{
int fd;
char buf[10]={"hello"};
char str[20]={0};
//open file
fd = open("/home/chenhai/test/a.txt",O_RDWR);
if(fd == -1)
{
printf("open a.txt faild\n");
}
else
{
printf("open a.txt ok\n");
}
//write file
int ret = write(fd,buf,10);
if(ret == -1)
{
printf("write a.txt faild\n");
}
else
{
printf("write a.txt ok\n");
}
#if 1
close(fd);
fd = open("/home/chenhai/test/a.txt",O_RDWR);
if(fd == -1)
{
printf("open faild !!\n");
}
else
{
printf("open success again\n");
}
#endif
int val = read(fd,str,20);
if(val == -1)
{
printf("read faild!!!\n");
}
else
{
printf("read ok,the value is: %s\n",str);
}
return 0;
}
通过man手册查看read的使用方法
NAME
read - read from a file descriptor
读 从 文件描述符
SYNOPSIS
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数一:需要读取的文件描述符
参数二:读取后的数据缓存地址
参数三:需要读取的数据大小
返回值: 成功 返回读取到字节数
0 已经读到文件的末尾了
-1 读取错误
注意: 读函数,他只会根据文本中的内容去读取。 假设文本中只有10 个字节的数据,
用户要求读取100个字节的数据,那么最终只会读到 10个!!! (因为它都没得给你读取啊。。。。。)
所以利用读取函数的时候,都是“越界"读取,要求读取的数据大小,要比文件中数据的真实大小要大!!!!