Linux的文件IO函数以及库的创建与使用

概念

  • 文件IO是没有缓冲区的,只有标准IO有缓冲区
  • 文件IO函数是由操作系统提供的,与操作系统绑定,又称之为系统调用
  • 文件IO函数是通过文件描述符来维护一个文件

文件描述符

  • 当我们要去操作一个文件的时候首先要打开一个文件。尝试打开一个文件的时候,系统会自动给这个文件分配一个编号,这个编号就是文件描述符,用文件描述符来维护描述这个文件

  • 标准IO是对文件IO的二次封装,最终标准IO依然会去调用文件IO,所以FILE结构体中会有文件描述符成员_fileno

    • 在文件IO的基础上,封装了一个缓冲区,同时将文件描述符也一起封装到了FILE结构体中
  • 文件描述符的本质

    • 文件描述符的本质是数组下标,该数组的容量默认为1024,范围是[0,1023]

    • 文件描述符是有上限的,所以在不使用的情况下,需要关闭

    • 获取文件描述符的规则是,从小向大,依次获取,直到找到一个没有被使用的元素,返回该元素的下标。

    • 其中有三个特殊的文件描述符,分别为0,1,2

      特殊的流指针(FILE*)特殊文件描述符结构体位置
      FILE *stdin0stdin->_fileno
      FILE *stdout1stdout->_fileno
      FILE *stderr2stderr->_fileno
  • getdtablesize(void)获取一个进程最多能打开几个文件描述符

文件IO函数

open

  • 功能:打开一个文件

  • 原型:

    •   #include <sys/types.h>
        #include <sys/stat.h>
        #include <fcntl.h>
        
        int open(const char *pathname, int flags, ...);
        int open(const char *pathname, int flags);
        int open(const char *pathname, int flags, mode_t mode);
      
  • 参数:

    • char *pathname:指定要打开的文件路径以及名字

    • int flags:打开方式

      • 参数功能
        O_RDONLY只读
        O_WRONLY只写
        O_RDWR读写
      • 以上三种,必须且只能包含一个

        参数功能
        O_APPEND追加的方式
        O_CREAT如果文件不存在则创建
        O_TRUNC如果文件存在,则清空
      • 如果需要多个选项,可以用按位或连接

    • mode_t mode:在文件创建时,指定文件的权限使用

      ​ 当flags中指定了O_CREAT或者O_TMPFILE的时候,mode参数必须填写

      ​ 当flags没有指定上述两种选项,则mode参数会被忽略

  • 返回值:

    • 成功:返回新的文件描述符
    • 失败:返回-1,更新errno
  • fopen的打开方式,在open中组合

    • fopenopen
      rO_RDONLY
      wO_WRONLY |O_CREAT|O_TRUNC
      aO_WRONLY|O_CREAT|O_APPEND
      r+O_RDWR
      w+O_RDWR|O_CREAT|O_TRUNC
      a+O_RDWR|O_CREAT|O_ARREND

close

  • 功能:关闭文件,释放文件描述符对应的该空间

  • 原型

    •   #include <unistd.h>
        int close(int fd);
      
  • 参数:

    • int fd:指定要关闭的文件
  • 返回值:

    • 成功:0
    • 失败:-1,更新errno

write

  • 功能:将数据写入文件中

  • 原型:

    •   #include <unistd.h>
        ssize_t write(int fd, const void *buf, size_t count);
      
  • 参数

    • int fd:指定要写入哪个文件中,填对应的文件描述符
    • void *buf:指定要输出的数据首地址,可以输出任意类型的数据
    • size_t count:指定要输出的数据大小,以字节为单位
  • 返回值:

    • 成功:返回成功输出的字节数
    • 失败:返回-1,更新errno

read

  • 功能:从指定的文件中读取数据

  • 原型:

    •   #include <unistd.h>
        ssize_t read(int fd, void *buf, size_t count);
      
  • 参数

    • int fd:指定要读取哪个文件,填对应的文件描述符
    • void *buf:存储读取到的数据
    • size_t count:指定要读取多少个字节
  • 返回值

    • >0:成功,返回成功读取到的字节数
    • =0:读取到文件结尾
    • -1:失败,返回-1,更新errno
  • read不会自动补充\0字符

  • read函数遇到\n不会停止读取

lseek

  • 功能:修改文件偏移量

  • 原型:

    •   #include <sys/types.h>
        #include <unistd.h>
        off_t lseek(int fd, off_t offset, int whence);
      
  • 参数:

    • int fd:指定要修改哪个文件偏移量,填上对应的文件描述符
    • off_t offset:偏移量,新的位置为whence加上offset参数
      • 往结尾偏移,填正数
      • 往开头偏移,填负数
    • int whence
      • SEEK_SET,文件开头位置
      • SEEK_CUR,文件当前位置
      • SEEK_END,文件结尾位置
  • 返回值

    • 成功:返回文件偏移后的当前位置,距离文件开头的偏移量
    • 失败,返回(off_t)-1,更新errno
  • lseek(fd, 0, SEEK_END);,返回值为文件的大小

文件属性相关函数

stat

  • 功能:获取文件所有属性

  • 原型:

    •   #include <sys/types.h> 
        #include <sys/stat.h> 
        #include <unistd.h> 
        int stat(const char *pathname, struct stat *statbuf);
      
  • 参数

    • char *pathname:指定要获取哪个文件的属性,填上对应的文件路径以及文件名

    • struct stat *statbuf:存储获取到的文件属性

//结构体类型
struct stat { 
                           dev_t     st_dev;         /* 设备信息 */ 
                           ino_t     st_ino;         /* inode号 */                 
                           mode_t    st_mode;        /* 文件类型以及文件权限 */           
                           nlink_t   st_nlink;       /* 硬链接数 */         
                           uid_t     st_uid;         /* 文件所属用户的id号 */                   
                           gid_t     st_gid;         /* 文件所属组用户的id号gid */            
                           dev_t     st_rdev;        /* 设备ID */ 
                           off_t     st_size;        /* 文件大小,单位字节 */         
                           blksize_t st_blksize;     /* 一个IO块大小 */ 
                           blkcnt_t  st_blocks;      /* 块个数 */ 
             
                           struct timespec st_atim;  /* 最后一次被访问的时间 */         
                           struct timespec st_mtim;  /* 最后一次被修改的时间 */   
                           struct timespec st_ctim;  /* 最后一次被改变状态的时间 */  
             
}; 
  • 返回值:

    • 成功:返回0
    • 失败:返回-1
  • stat获取文件权限方法

     需要使用 st_mode & 0777   --->得到文件权限
              S_ISUID     04000   set-user-ID bit
              S_ISGID     02000   set-group-ID bit (see below)
              S_ISVTX     01000   sticky bit (see below)
    
              S_IRWXU     00700   当前用户的读、写、可执行
              S_IRUSR     00400   当前用户读权限
              S_IWUSR     00200   当前用户写权限
              S_IXUSR     00100   当前用户可执行权限
    
              S_IRWXG     00070   当前组的读、写、可执行
              S_IRGRP     00040   当前组读权限
              S_IWGRP     00020   当前组写权限
              S_IXGRP     00010   当前组可执行权限
    
              S_IRWXO     00007   其他用户的读、写、可执行
              S_IROTH     00004   其他用户的读权限
              S_IWOTH     00002   其他用户的写权限
              S_IXOTH     00001   其他用户的可执行权限
  • stat获取文件类型方法
需要使用 st_mode & S_IFMT    --->得到文件权限
           S_IFMT     0170000   bit mask for the file type bit field
 
           S_IFSOCK   0140000   socket
           S_IFLNK    0120000   symbolic link
           S_IFREG    0100000   regular file
           S_IFBLK    0060000   block device
           S_IFDIR    0040000   directory
           S_IFCHR    0020000   character device
           S_IFIFO    0010000   FIFO

操作目录相关的函数

opendir

  • 功能:打开目录

  • 原型:

    •   #include <sys/types.h> 
        #include <dirent.h> 
        DIR *opendir(const char *name);
      
  • 参数

    • char *name:指定要打开的目录路径以及名字
  • 返回值

    • 成功:返回目录流指针,DIR*
    • 失败:返回NULL

closedir

  • 功能:关闭目录

  • 原型

    •   #include <sys/types.h>
        #include <dirent.h> 
        int closedir(DIR *dirp); 
      

readdir

  • 功能:读取目录,可以获取到该目录下所有文件名字

  • 原型:

    •   #include <dirent.h>
        struct dirent *readdir(DIR *dirp); 
      
  • 返回值

    • 成功:返回结构体指针
    • 读取到文件结尾,返回NULL,不更新errno
    • 失败,返回NULL,更新errno
  • 结构体原型

    •   struct dirent { 
                       ino_t          d_ino;       /* inode号 */ 
                       off_t          d_off;       /* 偏移量 */ 
                       unsigned short d_reclen;    /* 结构体长度 */ 
                       unsigned char  d_type;      /* 文件类型  */
                       char           d_name[256]; /* 文件名 */ 
                   }; 
      

Linux中的库

  • 库在系统中,是一个二进制文件,它是由源文件(不包含main函数)编译而来的,其他程序可以引入该文件中的库,并使用该文件中的相关函数

静态库

  • 一个XXX.c的源文件,编译生成一个libXXX.a的二进制文件,当你需要使用这个源文件中的函数时,只需要将对应的库连接到自己的可执行程序即可。
    • 静态体现在,使用gcc编译时,会将该库封装进可执行程序,当使用该库中的函数时,可执行程序直接使用即可,因为该库已经该可执行程序的一部分
    • 缺点:库会占用可执行文件的大小
    • 优点:调用方便,效率高

在这里插入图片描述

编译生成静态库

gcc  -c add.c -o add.o                   -->    只编译不连接,生成二进制文件
ar -crs libadd.a  add.o                  -->    基于add.o生成一个静态库
 
ar:生成静态库的指令
-c:创建
-r:将文件插入或者替换静态库中同名的文件
-s:重置静态库的索引

在这里插入图片描述

静态库的使用

gcc 主程序.c -L 库的路径 -l库名 -I 头文件路径
 
-L:指定库所在的路径
-l:指定库名
-I:指定头文件所在路径

动态库

  • 一个XXX.c的源文件,编译生成一个libXXX.a的二进制文件,当你需要使用这个源文件中的函数时,只需要将对应的库连接到自己的可执行程序即可。
    • 动态体现在:在使用gcc编译的时候,会将该库对应的函数表封装在可执行程序中,当使用该库中的函数时,可执行程序需要通过该表找到库所在的位置,并且调用该库中的函数。
    • 缺点:调用时需要去找到库所在的位置,并调用 ,效率较低
    • 优点:库会不会占用可执行文件太多的空间,多个可执行程序可以共同连接到一个库中,所以,动态库也称为共享库

在这里插入图片描述

生成动态库

gcc  -fPIC -c add.c -o add.o               //-fPIC 忽略文件位置进行编译,将add.c编译程式add.o
gcc -shared add.o -o libadd.so         //依赖于二进制文件生成一个动态库
 
上面两个指令可以把合成一个指令
gcc -fPIC -shared add.c -o libadd.so

使用动态库

gcc 主程序.c -L 库的路径 -l库名 -I 头文件路径
 
-L:指定库所在的路径
-l:指定库名
-I:指定头文件所在路径

动态库使用异常

在这里插入图片描述

解决方式一
1、在命令行中输入定义当前库的路径
        export LD_LIBRARY_PATH = 库的路径
方法二
2、将该库直接放在/lib目录夏,或者/usr/lib目录下
 sudo mv libadd.so /lib
 sudo mv libadd.so /usr/lib
方法三
3、直接更改库的配置文件
    sudo vi /etc/ld.so.conf.d/libc.conf 

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值