• Linux学习笔记7-文件IO编程(一)


    1.系统调用及用户编程接口

    1.1. 系统调用:
    • 指操作系统(OS)提供给用户程序(APP)调用的一组“特殊”接口,用户程序(APP)可以通过这组“特殊”接口来获得操作系统内核(OS Kernel)提供的服务。
    • 在 Linux 中,为了更好地保护内核空间,将程序的运行空间分为 内核空间用户空间(也就是常称的 内核态用户态),它们分别运行在不同的级别上,在逻辑上是相互隔离的.因此,用户进程在通常情况下不允许访问内核数据,也无法使用内核函数,它们只能在用户空间操作用户数据,调用用户空间的函数。在有些情况下,用户空间的进程需要获得一定的系统服务(调用内核空间程序),这时操作系统就必须利用系统提供给用户的“特殊接口”,即系统调用规定用户进程进入内核空间的具体位置,进行系统调用时,程序运行空间需要从用户空间进入内核空间,处理完后再返回用户空间
    • Linux 系统调用部分是非常精简的系统调用(只有 250 个左右),它继承了 UNIX 系统调用中最基本和最有用的部分。这些系统调用按照功能逻辑大致可分为进程控制进程间通信文件系统控制系统控制存储管理网络管理socket 控制用户管理等几类。
    系统调用
    进程控制
    进程间通信
    文件系统控制
    系统控制
    存储管理
    网络管理
    socket控制
    用户管理
    1.2.用户编程接口:
    • 系统调用并不是直接与程序员进行交互的,它仅仅是一个通过软中断(Soft Interrupt)机制向内核提交请求(Request),以获取内核(Kernel)服务的接口。在实际使用中程序员调用的通常是用户编程接口。
    • 在 Linux 中,用户编程接口(API)遵循了在 UNIX 中最流行的应用编程界面标准 — POSIX 标准,其是由 IEEE 和 ISO/IEC 共同开发的标准系统。该标准基于当时现有的 UNIX 实践和经验,描述了操作系统(OS)的系统调用编程接口(即 API),用于保证应用程序可以在源代码一级上在多种操作系统上移植运行。这些系统调用编程接口主要是通过 C 库(libc)实现的。
      • POSIX:可移植操作系统接口(Portable Operating System Interface of UNIX,缩写为 POSIX

    2.文件及文件描述符

    • 2.1.在 Linux 中对目录和设备的操作都等同于文件的操作,其极大的简化了系统对不同设备的处理,提高了效率。

    • 2.2.Linux 中的文件主要分为 4 种:普通文件、目录文件、链接文件和设备文件(详细见章节文件系统)。

    • 2.3.为了区分 Linux 中内核和引用特定的文件,采用文件描述符(fd)这一概念,对于 Linux 而言,所有对设备和文件的操作都是使用文件描述符来进行的(即一切皆文件)。

    • 2.4.文件描述符是一个非负的整数(fd>=0),它是一个索引值,并指向在内核中每个进程打开文件的记录表。当打开一个现存文件或创建一个新文件时,内核就向进程返回一个文件描述符;当需要读写文件时,也需要把文件描述符作为参数传递给相应的函数。

    • 2.5.一个进程启动时,都会打开 3 个文件:标准输入标准输出标准出错 处理。这 3 个文件分别对应文件描述符(fd)为: 0(STDIN_FILENO)、1(STDIN_FILENO) 和 2(STDERR_FILENO)。

    3.底层文件I/O操作

    • 文件I/O操作的系统调用,主要用到5个函数:open()close()read()write()lseek()。这些函数的特点是不带缓存,直接对文件(包括设备)进行读写操作。这些函数虽然不是 ANSI C 的组成部分,但是 POSIX 的组成部分。

      • open() 函数用于打开或创建文件,在打开或创建文件时可以指定文件的属性及用户的权限等各种参数

      • close() 函数用于关闭一个被打开的文件。当一个进程终止时,所有被它打开的文件都由内核自动关闭,很多程序都使用这一功能而不显示地关闭一个文件。

      • read() 函数用于将从指定的文件描述符中读出的数据放到缓存区中,并返回实际读入的字节数。若返回 0,则表示没有数据可读,即已达到文件尾。读操作从文件的当前指针位置开始。当从终端设备文件中读出数据时,通常一次最多读一行。

      • write() 函数用于向打开的文件写数据,写操作从文件的当前指针位置开始。对磁盘文件进行写操作,若磁盘已满或超出该文件的长度,则 write()函数返回失败。

      • lseek() 函数用于在指定的文件描述符中将文件指针定位到相应的位置。它只能用在可定位(可随机访问)文件操作中管道、套接字大部分字符设备文件不可定位的,所以在这些文件的操作中无法使用 lseek()。

    底层文件I/O操作
    open函数
    打开或创建文件
    不带缓存,直接对文件,包括设备进行读写操作
    read函数
    从指定的文件描述符中读出的数据放到缓存区中,并返回实际读入的字节数
    write函数
    向打开的文件写数据,写操作从文件的当前指针位置开始
    lseek函数
    在指定的文件描述符中将文件指针定位到相应的位置
    close函数
    关闭一个被打开的文件

    4.文件锁

    • 在文件已经共享的情况下,也就是当多个用户共同使用、操作一个文件的情况,此时在Linux中通常采用是给文件上锁,来避免共享的资源产生竞争的状态。

    • 文件锁包括 建议性锁强制性锁

      • 建议性锁要求每个上锁文件的进程都要检查是否有锁存在,并且尊重已有的锁。在一般情况下,内核和系统都不使用建议性锁
      • 强制性锁是由内核执行的锁,当一个文件被上锁进行写入操作的时候,内核将阻止其他任何文件对其进行读写操作
        • 采用强制性锁对性能的影响很大,每次读写操作都必须检查是否有锁存在。
    • 在Linux中,实现文件上锁的函数有 lockf()fcntl(),其中 lockf() 用于对文件施加建议性锁,
      fcntl() 不仅可以施加建议性锁,还可以施加强制锁。同时 fcntl() 还能对文件的某一记录上锁,也就是 记录锁

    Linux文件锁函数
    lockf函数
    建议性锁函数
    fcntl函数
    具备建议性锁,强制锁,记录锁三者功能的函数
    • 记录锁 又可分为 读取锁写入锁
      • 读取锁又称为 共享锁,它能够使多个进程都能在文件的同一部分建立读取锁
      • 写入锁又称为 排斥锁在任何时刻只能有一个进程在文件的某个部分上建立写入锁。当然,在文件的同一部分不能同时建立读取锁和写入锁
    记录锁
    读取锁,又称共享锁
    它能够使多个进程都能在文件的同一部分建立读取锁
    写入锁,又称排斥锁
    在任何时刻只能有一个进程在文件的某个部分上建立写入锁

    参考文献:《Linux嵌入式应用程序开发标准教程》

  • 相关阅读:
    mybatispagehelp嵌套分页处理
    微信支付APIV3统一回调接口封装(H5、JSAPI、H5、App、小程序)
    (续)SSM整合之spring笔记(AOP 动态代理)(P094—P098)
    Redis7--基础篇2(Redis的十大数据类型及常用命令)
    高并发技巧-流量聚合和高并发写入处理技巧
    C专家编程 第8章 为什么程序员无法分清万圣节和圣诞节 8.6 不需要按回车就能得到一个字符
    序列模型相关
    【SpringBoot】必须掌握的45个注解
    五、编译预处理
    VM Tools安装过程
  • 原文地址:https://blog.csdn.net/weixin_43940932/article/details/127405831