5.文件I/O

1  C标准函数与系统函数的区别

文件的结构体:

1.1  I/O缓冲区

  每一个FILE文件流都有一个缓冲区buffer,默认大小8192Byte。

1.2  效率

  文件缓冲区会降低效率。这里提供缓冲区主要是为了减少磁盘的读取。

1.3  程序的跨平台性

  事实上Unbuffered I/O这个名词是有些误导的,虽然write系统调用位于C标准库I/O缓
冲区的底层,但在write的底层也可以分配一个内核I/O缓冲区,所以write也不一定是直接
写到文件的,也可能写到内核I/O缓冲区中,至于究竟写到了文件中还是内核缓冲区中对于
进程来说是没有差别的,如果进程A和进程B打开同一文件,进程A写到内核I/O缓冲区中的数
据从进程B也能读到,而C标准库的I/O缓冲区则不具有这一特性。

如图所示:

 

2    PCB概念

2.1  ask_struct结构体

/usr/src/linux-headers/include/linux/sched.h  (这里的linux-headers每一用户不一样,直接按tab键补齐,或者手动cd进入目录)

如图所示:

扫描二维码关注公众号,回复: 81338 查看本文章

2.2  files_struct结构体 (打开文件的描述表)

 

模型如下:

 

3  open/close

 

 3.1  文件描述符

  一个进程默认打开三个文件描述符

STDIN_FILENO 0
STDOUT_FILENO 1
STDERR_FILENO 2

  新打开文件返回文件描述符表中未使用的最小文件描述符。

  open函数可以打开或创建一个文件

1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 int open(const char *pathname, int flags);
5 int open(const char *pathname, int flags, mode_t mode);
6 返回值:成功返回新分配的文件描述符,出错返回-1并设置errno

 

 1 #include <stdlib.h>
 2 #include <stdio.h>
 3 #include <sys/types.h>
 4 #include <sys/stat.h>
 5 #include <fcntl.h>
 6 
 7 
 8 int main()
 9 {
10     int fd=0;
11     //打开文件,如果文件不存在则创建,权限为0777
12     fd = open("abc",O_CREAT,0777);
13     printf("fd = %d\n",fd);
14     return 0;
15 }

运行效果:

权限为0777-0002 = 0775 换算成二进制 111 111 101 rwx rwx r-x

 在Man Page中open函数有两种形式,一种带两个参数,一种带三个参数,其实在C代码
中open函数是这样声明的:

int open(const char *pathname, int flags, ...);

  最后的可变参数可以是0个或1个,由flags参数中的标志位决定,见下面的详细说明。
pathname参数是要打开或创建的文件名,和fopen一样,pathname既可以是相对路径也
可以是绝对路径。flags参数有一系列常数值可供选择,可以同时选择多个常数用按位或运
算符连接起来,所以这些常数的宏定义都以O_开头,表示or。

  必选项:以下三个常数中必须指定一个,且仅允许指定一个。
  * O_RDONLY 只读打开
  * O_WRONLY 只写打开
  * O_RDWR 可读可写打开

以下可选项可以同时指定0个或多个,和必选项按位或起来作为flags参数。可选项有很多,
这里只介绍一部分,其它选项可参考open(2)的Man Page:
  * O_APPEND 表示追加。如果文件已有内容,这次打开文件所写的数据附加到文件的末尾
  而不覆盖原来的内容。
  * O_CREAT 若此文件不存在则创建它。使用此选项时需要提供第三个参数mode,表示该
  文件的访问权限。
  * O_EXCL 如果同时指定了O_CREAT,并且文件已存在,则出错返回。
  * O_TRUNC 如果文件已存在,并且以只写或可读可写方式打开,则将其长度截断(Truncate)为0字节。
  * O_NONBLOCK 对于设备文件,以O_NONBLOCK方式打开可以做非阻塞I/O(Nonblock I/
  O),非阻塞I/O在下一节详细讲解。

 1 #include <stdlib.h>
 2 #include <stdio.h>
 3 #include <sys/types.h>
 4 #include <sys/stat.h>
 5 #include <fcntl.h>
 6 #include <unistd.h>
 7 
 8 int main(int argc,char *argv[])
 9 {
10     int fd=0;
11     char buf[]="helloworld";
12     //打开文件,如果文件不存在则创建,默认权限为750
13     //创建,读写权限
14     //fd = open("1233",O_CREAT | O_RDWR);
15     fd = open("1233",O_CREAT | O_RDWR|O——APPEND);
16     write(fd,buf,sizeof(buf));
17     printf("fd = %d\n",fd);
18     return 0;
19 }

3.2  最大打开文件个数

查看当前系统允许打开最大文件个数

cat /proc/sys/fs/file-max

查看当前默认设置最大打开文件个数 

ulimit -a

修改默认设置最大打开文件个数为4096

ulimit -n 4096

4  read/write

  read函数从打开的设备或文件中读取数据。

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
返回值:成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则这次read返回0

  参数count是请求读取的字节数,读上来的数据保存在缓冲区buf中,同时文件的当前读
写位置向后移。注意这个读写位置和使用C标准I/O库时的读写位置有可能不同,这个读写
位置是记在内核中的,而使用C标准I/O库时的读写位置是用户空间I/O缓冲区中的位置。比
如用fgetc读一个字节,fgetc有可能从内核中预读1024个字节到I/O缓冲区中,再返回第一
个字节,这时该文件在内核中记录的读写位置是1024,而在FILE结构体中记录的读写位置是
1。注意返回值类型是ssize_t,表示有符号的size_t,这样既可以返回正的字节数、0(表
示到达文件末尾)也可以返回负值-1(表示出错)。read函数返回时,返回值说明了buf中
前多少个字节是刚读上来的。有些情况下,实际读到的字节数(返回值)会小于请求读的字
节数count,例如:
  读常规文件时,在读到count个字节之前已到达文件末尾。例如,距文件末尾还有30个
字节而请求读100个字节,则read返回30,下次read将返回0。
  从终端设备读,通常以行为单位,读到换行符就返回了。
  从网络读,根据不同的传输层协议和内核缓存机制,返回值可能小于请求的字节数,后
面socket编程部分会详细讲解。
  write函数向打开的设备或文件中写数据。

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
返回值:成功返回写入的字节数,出错返回-1并设置errno

  写常规文件时,write的返回值通常等于请求写的字节数count,而向终端设备或网络写
则不一定。


 

 

 

猜你喜欢

转载自www.cnblogs.com/xiaochi/p/8963892.html