• 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进入目录)

    如图所示:

    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
    ",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
    ",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,而向终端设备或网络写
    则不一定。

    拷贝文件程序:

     1 #include <unistd.h>
     2 #include <sys/stat.h>
     3 #include <sys/types.h>
     4 #include <fcntl.h>
     5 #include <stdlib.h>
     6 #include <stdio.h>
     7 #define SIZE 8192
     8 
     9 int main(int argc,char *argv[])
    10 {
    11     char buf[SIZE];
    12     int fd_src,fd_dest,len;
    13     
    14     if(argc<3){
    15         printf("./mycp src dest
    ");
    16         exit(1);
    17     }
    18     
    19     fd_src = open(argv[1],O_RDONLY);
    20     fd_dest = open(argv[2],O_CREAT|O_WRONLY|O_TRUNC,0777);
    21     
    22     //成功返回读到的字节数,读到文件末尾返回0,读失败返回-1
    23     while( (len = read(fd_src,buf,sizeof(buf))) >0)
    24     {
    25         write(fd_dest,buf,len);
    26     }
    27     
    28     close(fd_src);
    29     close(fd_dest);
    30     
    31     return 0;
    32 }

     输出屏幕输入信息:

    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/stat.h>
    
    int main()
    {
        char buf[1024];
        
        int len = read(STDIN_FILENO,buf,sizeof(buf));
        write(STDOUT_FILENO,buf,len);
        
        return 0;
    }


     

     

     

  • 相关阅读:
    Vue 页面权限控制和登陆验证
    Vue 动态添加路由及生成菜单
    开发一个简单的 Vue 弹窗组件
    VS使用和错误收集
    ARP欺骗的实现
    虚拟机安装64位系统(Windows Server 2008R2 Datacenter版本)
    Kali安装问题
    HTML5学习之四:多媒体播放
    HTML5学习之三:文件与拖放
    HTML5学习之二:HTML5中的表单2
  • 原文地址:https://www.cnblogs.com/xiaochi/p/8963892.html
Copyright © 2020-2023  润新知