欢迎光临
我们一直在努力

Linux之文件--基础IO

什么是文件

a.文件=文件内容+文件属性

对文件的操作

1.对文件内容

2.对文件属性

b.访问文件之前,必须先打开文件,打开文件需要文件得地址,

看下面这个案例,为什么这里我们没有文件的路径,他直接在当前路径下新建了一个文件呢???

其实是当这个可执行程序运行起来的时候已然变成了一个进程,而一个进程是会动态维护自己的cwd,当你没有给他路径时,他就会默认在当前的工作路径中创建文件了

c.打开文件实际上是在把文件加载到内存中,进程要访问什么,就把什么加载到内存,让cpu访问内存的文件

d.linux存在大量的文件,文件分为,打开和未打开的文件.打开的在内存,未打开在磁盘

e.linux中,可以存在很多被打开的文件,操作系统要对那么多的文件进行管理,要先描述在组织

一些基础文件操作

fopen

fopen里面的mode有众多选项

基础 6 种模式
  • r 只读;文件必须存在;文件指针在开头;不能写。
  • r+ 可读可写;文件必须存在;指针在开头;覆盖原有内容。
  • w 只写;文件不存在则创建;文件存在立刻清空 (truncate);指针在开头。
  • w+ 可读可写;不存在则创建;存在直接清空;指针在开头。
  • a 追加只写;不存在则创建;指针固定在文件末尾;只能新增,不能修改原有内容。
  • a+ 可读 + 追加写;不存在则创建;

  • w模式

    没有文件,就在当前目录下面新增文件

    存在文件,就将文件内容清空

    和echo的输出重定向很像

    根据写的这个特征我们可以写一个小demo实现清空文件内容的文件


    a模式

    追加只写;不存在则创建;

    不存在则创建;

    和echo的追加很相似


    如何理解

    fputs

    • 参数 1:要输出的字符串
    • 参数 2:必须是文件指针 FILE*

    我们向log.txt文件里面写入

    fgets

  • s:字符缓冲区,存放读到的字符串
  • size:缓冲区最大容量
  • stream:文件流(stdin / 文件指针FILE*)
  • fgets

  • 读到 换行符 \\n → 停止(正常一行结束)
  • 读到 size-1 个字符 → 停止(缓冲区填满)
  • 读到文件末尾 EOF → 停止
  • 因为读到换行符就停止所以之会打印一行

    linux进行文件操作

    open

    1. 参数说明
  • const char *pathname 文件路径字符串,支持相对路径、绝对路径。
  • int flags(必选,文件打开标志,按位或组合) 基础访问模式(三选一,不可同时多个):
    • O_RDONLY:只读
    • O_WRONLY:只写
    • O_RDWR:读写

    常用附加标志:

    • O_CREAT:文件不存在则创建;使用该标志时,必须带上第三个参数 mode
    • O_TRUNC:若文件存在且以写方式打开,清空文件内容
    • O_APPEND:写操作追加到文件末尾
    • O_NONBLOCK:非阻塞打开

    在调用之前我们来看这个例子理解一下

    这段代码是位标记(Bit Flag / 位掩码)经典示例,open 函数 flags 参数原理

    (1)| 按位或:组合多个标记

    (2)& 按位与:检测某个标记是否存在

    例子

    我们这里打开文件只给系统的写权限,但是发现,原来文件里面没有,他并不会为我们新创建一个,反而是打开失败,系统本身的文件操作和c语言是不同的

    这里我们加上了创建的操作,事实上却是也为我们创建了,但是我们发现权限是乱的

    此时需要我们给出新建文件的权限

    对于第二个open->mode,是解决如果文件不存在要怎么创建问题的解决也就是文件权限

    我们给的是666,为什么文件却是664

    这是因为umask,权限掩码

    我们在c代码里面设置umask变为0即可完成刚刚的要求


    文件描述符是3,为什么是三呢???

    稍后回答

    2. 返回值
    • 成功:返回非负整数文件描述符 fd
    • 失败:返回 -1,同时设置全局变量 errno

    close关闭文件

      write

      我们发现系统的write是覆盖式的写不会对原内容进行清空再写

      想要写入时,将原来的内容清空就加上 O_TRYNC

      追加式写入O_APPEND


      c对系统的封装理解

      我们再来看下面一个现象

      为什么没有0,1,2???

      因为系统已经占用了前三个文件描述符

      如果说0,1,2被占用,那么我们用write写应该是可以实现的

      文件描述符名称标准库指针作用
      0 标准输入 stdin 读取键盘输入
      1 标准输出 stdout 输出到终端屏幕
      2 标准错误 stderr 错误信息输出到终端

      向屏幕进行输出

      当然c封装的函数也可以实现这一点

      也就是stdin,stdout,stderr结构体内存在文件描述符

      语言层面的文件操作vs系统的文件操作

      文件描述符的本质???

      读写文件时,内核配合页缓冲区:

    • 先把磁盘文件数据加载到内存缓冲区
    • 程序在缓冲区修改数据
    • 合适时机(主动 fsync / 缓冲区满)把缓冲区数据写回磁盘
    • 每一个进程(struct task_struct)内部包含一个 struct files_struct, 里面维护一张指针数组:struct file *fd_array[],这就是文件描述符表。

      • 数组下标 = 文件描述符 fd(0、1、2、3、4……)
      • 数组元素是指针,指向内存中对应的struct file

      所以呢,文件描述符就是数组下标,操作系统也只认文件标识符

      为什么c要对系统进行封装,理解IO

      系统调用(open/read/write/close)是操作系统提供的原生接口,运行陷入内核态;C 标准库在此之上封装出 FILE* 系列 IO 函数,本质就是用户态缓冲层封装。

      1. 跨平台可移植
      • open/read/write 是 Linux/Unix 特有系统调用,Windows 没有这套 API(Windows 用CreateFile)。
      • C 标准库 fopen/fwrite 语言标准规定,编译器在不同系统底层自动适配对应系统接口。一份代码不用修改,就能在 Linux、Windows、macOS 编译运行。
      • 可以让更多人使用
      2. 引入用户态缓冲区,减少系统调用次数

      系统调用存在内核态 / 用户态切换开销,频繁调用read/write性能很差。

      • 标准库FILE内部自带一块用户缓冲区;
      • fprintf/fputs先把数据写到缓冲区,缓冲区填满后,才一次性调用write系统调用刷入内核;
      • 大幅减少系统调用次数,提升 IO 效率。
      赞(0)
      未经允许不得转载:171主机测评 » Linux之文件--基础IO
      分享到: 更多 (0)

      评论 抢沙发

      • 昵称 (必填)
      • 邮箱 (必填)
      • 网址