• Linux 文件操作接口


    Linux 文件操作接口

    在使用语言编写服务的时候不乏会遇到需要对文件进行操作的场景,Linux内核是用C语言写的,了解Linux之前先熟悉一下C语言文件操作接口,方便对比。

    C语言文件操作接口

    C语言文件描述

    #ifndef _FILE_DEFINED
    struct _iobuf {
        char *_ptr; //文件输入的下一个位置
        int _cnt; //当前缓冲区的相对位置
        char *_base; //指基础位置(即是文件的起始位置)
        int _flag; //文件标志
        int _file; //文件描述符id
        int _charbuf; //检查缓冲区状况,如果无缓冲区则不读取
        int _bufsiz; //文件缓冲区大小
        char *_tmpfname; //临时文件名
    };
    typedef struct _iobuf FILE;
    #define _FILE_DEFINED
    #endif

    C语言对文件操作需要的数据都存在这样的数据结构里,C语言对文件操作时,用一个数据结构唯一标识一个文件流

    fopen()

    FILE* fopen(const char *path, const char *mode);

    返回值为文件流结构体指针,当打开失败时返回NULL指针。
    对文件操作前需先打开文件,打开文件使用接口fopen()。

    参数:
    path: 文件路径,可以是相对路径也可以是绝对路径(默认为进程打开时路径)
    mode: 打开方式

    模式 含义 文件不存在时
    r 只读 报错
    w 只写 创建文件
    a 追加只写 创建文件
    rb 二进制只读 报错
    wb 二进制只写 创建文件
    ab 二进制追加只写 创建文件
    r+ 读写 报错
    w+ 读写 创建文件
    a+ 追加读写 创建文件
    rb+ 二进制读写 报错
    wb+ 二进制读写 创建文件
    ab+ 二进制追加读写 创建文件

    以上打开模式凡带'b'操作的打开文件时都会清空文件。

    r模式打开文件

    image-20221020211618640)
    文件不存在时打开失败
    image-20221020211643933
    文件存在时打开成功

    w模式打开文件

    image-20221020211705345
    自动创建需要打开的文件
    image-20221020211943645
    打开后会清空文件

    a模式打开文件

    image-20221020212350468

    image-20221020212437360

    image-20221020212614385

    以a模式打开文件不存在时创建文件,存在时在文件末尾写入内容。

    其他模式类似

    fclose()

    C语言程序员要养成用完即释放的好习惯尽量避免内存泄漏,fclose() 接口就是用来关闭文件流的。

    int fclose(FILE *fp);

    关闭接口参数简单,只需将需要关闭的文件流指针传入即可。

    fwrite()

    size_t fwrite(const void *ptr, size_t size, size_t number, FILE *stream);

    参数:
    ptr: 写入文件的内容
    size: 写入单位数据大小(byte)
    number: 写入数据总数
    stream: 文件流

    image-20221020221422346

    写入操作传参如图

    fread()

    size_t fread(void *ptr, size_t size, size_t number, FILE *stream);

    参数类似fwrite()
    ptr 为要读入文件内容的容器,必须提前开好空间,number 不得大于实际开好的空间

    image-20221020223117974

    image-20221020223223523

    读文件操作如图

    系统文件操作接口

    文件描述符fd

    文件描述符可以唯一标识该进程打开的流。

    open()

    int open(const char *pathname, int flags);
    int open(const char *pathname, int flags, mode_t mode);

    参数:
    pathname: 文件路径,默认为进程创建时的路径
    flags: 决定文件打开模式
    mode: 创建文件时文件权限

    理解标记位原理

    计算机中所有数据都由比特位组成,一个整形有32个比特位,用一位作为标记,一个int类型可以携带32个标识,并且可以随意组合。
    如下操作,想完成什么操作传入对应的标记即可。

    image-20221020225608466

    image-20221020230120754

    open()的常用标记

    标记 含义
    O_RDONLY 只读
    O_WRONLY 只写
    O_RDWR 读写
    O_APPEND 追加
    O_CREAT 创建文件
    O_TRUNC 清空文件

    image-20221020232112966

    image-20221020232216981

    将只读标记和创建文件标记传入open()接口,创建文件如图。文件创建出来了,但可以看出它的权限是乱的,可见这个接口不足以像fopen() 一样打开文件。

    image-20221020232755988

    image-20221020232840531

    使用另一个接口创建出来权限正常的文件,但权限还不是如我们所设想的设置什么权限码就创建什么权限文件。此问题与权限掩码umask有关

    image-20221020233338235

    权限码与umask取反再按位与最后得到的权限码才是最终权限码,若需只在该程序重设umask 只需使用接口umask:

    mode_t umask(mode_t mask);

    参数mask为想要重设的权限掩码

    image-20221020234520813

    image-20221020234411827

    现在所创建的文件权限就全如程序员所愿了。

    write()

    系统写文件操作接口

    ssize_t write(int fd, const void *buf, size_t count);

    操作与fwrite() 基本一致,参数buf 类型为void* ,count 为要写入内容大小(byte)。
    image-20221020235753477

    image-20221020235905836

    写入成功,但如上打开方式还有一个隐患:

    image-20221021000417536

    image-20221021000342764

    后写入的内容并不会在空文件写入,而是会在已有内容上进行覆盖,这样的操作可不像C语言的w操作,针对此问题可以再加一个标志O_TRUNC

    image-20221021000756908

    image-20221021000851606

    如此才可和C语言的fopen() 的 w 操作一致

    read()

    ssize_t read(int fd, void *buf, size_t count);

    read()参数与write() 基本一致,与fread() 操作相差不多,需要buf 提前开好空间
    image-20221021102426397

    image-20221021102507530

    当文件不存在时:

    image-20221021102719368

    如此,效果与fread() 一致

    close()

    使用完文件后需得关闭文件,尽量防止内存泄漏,使用close()接口

    int close(int fd);

    两种操作接口联系

    操作系统设计时为了安全任何高级语言操作文件都不能绕过操作系统,用户对文件操作只能通过操作系统提供的接口,而Linux操作系统内核主要用C语言编写,提供的接口也是用C语言编写的,C语言用户可以直接使用。C语言操作文件也需通过操作系统提供的接口,因此C语言的文件操作接口是对系统文件接口进行封装后暴露出来的。
    但既然已经有系统接口了为什么还要C语言文件操作接口,此问题原因有几个:

    1. 使用不方便(对比之前的fopen()open())
    2. C语言是跨平台语言,若使用系统文件操作接口,同一份代码移植到其他平台将会编译不通过,使用封装后的接口,可以完美解决这个问题

    高级语言都是用自己的语言特性封装系统接口来操作文件

    系统接口 语言接口
    open(const char* path, O_WRONLY | O_CREAT | O_TRUNC) fopen(const char* path, "w")
    open(const char* path, O_RDONLY) fopen(const char* path, "r")
    open(const char* path, W_WRONLY | O_CREAT |O_APPEND) fopen(const char* path, "a")
    close(int fd) fclose(FILE* fStream)
    write(fd, const void* buf, size_t count) fwrite(const void* ptr, size_t size, size_t number, FILE* fStream)
    read(fd, void* buf, size_t count) fread(void* ptr, size_t size, size_t number, FILE* fStream)

    C语言对封装的接口跨平台解决办法
    条件编译 + 穷举

  • 相关阅读:
    windows driver开发和双机调试环境搭建
    C++多态详解
    重装系统步骤(Win7换Win10)
    向毕业妥协系列之深度学习笔记(三)DL的实用层面(上)
    【Linux学习笔记】基础IO
    中秋的秋
    golang使用JWX进行认证和加密
    Rust vs C++ 深度比较
    git增加右键菜单
    一个普通双非女生的秋招之路
  • 原文地址:https://www.cnblogs.com/Pigern-jun/p/16812997.html