当前位置: 首页 > java >正文

【Linux】基础 IO(一)

📝前言:

这篇文章我们来讲讲Linux——基础IO主要包括:

  1. 文件基本概念
  2. 回顾 C文件的操作
  3. 介绍系统关于文件的基本操作

🎬个人简介:努力学习ing
📋个人专栏:Linux
🎀CSDN主页 愚润求学
🌄其他专栏:C++学习笔记,C语言入门基础,python入门基础,C++刷题专栏


目录

  • 一,基本概念
    • 1. 概念
    • 2. 系统角度
  • 二,C 文件的 IO
    • 1. 打开操作
    • 2. 写操作
    • 3. 读操作
    • 4. 默认打开的流
  • 三,系统文件的 IO
    • 1. 位标记传递
    • 2 系统调用 open
    • 3 读写的系统调用
      • 使用示例
      • 库函数和系统调用
    • 4 文件描述符(重点)
      • 文件描述符的分配原则

一,基本概念

1. 概念

  • 狭义:
    • 文件在磁盘上
    • 磁盘是永久性存储物质
    • 磁盘是外设,即是输入设备,也是输出设备
    • 对文件的操作,其实是对外设的输入和输出,称为 IO
  • 广义:
    • Linux 下⼀切皆文件
    • 文件 == 内容 + 属性

2. 系统角度

  • 对⽂件的操作本质是进程对⽂件的操作
  • 硬件(如磁盘)的管理者是操作系统
  • ⽂件的读写本质不是通过 C 语⾔ / C++ 的库函数来操作的(这些库函数只是为用户提供⽅便),底层是通过文件相关的系统调用接口来实现的

二,C 文件的 IO

1. 打开操作

fopen

  • FILE *fopen(const char *pathname, const char *mode);
    • pathname:文件路径
    • mode:打开方式
  • 返回:
    • 成功:返回文件指针
    • 失败:返回NULL

这个FILE的类型是一个文件结构体struct file,通过typedef来的

2. 写操作

写操作,在文件不存在的时候都会创建文件。

打开文件时的写入模式:

  • 清空写w:清空文件内容,重新写
  • 追加写a:在原来文件内容后面追加写

fwrite

  • size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
    • ptr的数据写到stream
    • size:每个数据项的大小,比如写intsiezeof(int)(就是4
    • nmemb:数据项的个数
  • 返回:实际成功写入的数据项数量

注意:文件写入的时候不能写入'\0''\0'是C语言的东西,写入了以后是乱码

示例:

  5 // C 语言文件接口回顾6 int main()7 {8     FILE* fp1 = fopen("log1.txt", "w");9     FILE* fp2 = fopen("log2.txt", "a");10     if(fp1 == NULL) printf("log1.txt 打开失败\n");11     if(fp2 == NULL) printf("log2.txt 打开失败\n");12     char* str1 = (char *)"测试写入\n";13     fwrite(str1, strlen(str1), 1, fp1);14     fwrite(str1, strlen(str1), 1, fp2);15     fclose(fp1);16     fclose(fp2);17     return 0;18 } 

当使用相对路径的时候,进程通过自己记录的自己工作路径CWD信息,知道新建的文件要放在哪里

运行结果:
在这里插入图片描述

3. 读操作

读操作,如果文件不存在会报错
fread

  • size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
    • 不解释了,和fwrite的都一样,不一样的就是stream是读入的流,ptr是存储读入数据的地方。
    • 在上一次读取结束后文件指针的位置继续读取。
  • 返回:实际成功读取的数据项数量

示例:

 20 int main()21 {22     FILE* fp = fopen("log2.txt", "r");23     if(fp == NULL) printf("打开文件失败");24 25 26     char* str1 = (char *)"测试写入\n";27     char buff[1024];28     while(1)29     {30         // 这里每次读都是覆盖写buff的,但是我们及时打印出来                                                                                                                                                  31         int s = fread(buff, 1, sizeof(str1), fp); // 这里每次读一个char,方便后续设置 '\0'32         if(s > 0)33         {34             buff[s] = 0;35             printf("%s", buff);36         }37         if(feof(fp))38             break;39     }40     return 0;41 }

运行结果:
在这里插入图片描述

4. 默认打开的流

#include <stdio.h>
extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;

C默认会打开三个输⼊输出流,分别是标准输入:stdin, 标准输出:stdout, 标准错误:stderr

三,系统文件的 IO

头文件:<unistd.h>

1. 位标记传递

利用位图进行标记位传递,假设,现有标记位:ONE : 0001TWO:0010THREE:0100

  • 如果我们单独传入一个ONE就相当于传递了最低位的1
  • 如果我们希望传递第最低位的1和次低位的1,就可以传入ONE | TWO(通过获的方式)

2 系统调用 open

系统,通过系统调用open打开文件:
在这里插入图片描述

  • pathname:文件路径
  • falgs:选项(约等于C语言里面的打开模式),通过 或|来实现传递多个选项【这个选项本质是宏实现的标记位】
  • 常见选项:
    • O_RDONLY:只读打开
    • O_WRONLY: 只写打开
    • O_RDWR : 读,写打开
  • 上面这三个常量,必须指定⼀个且只能指定⼀个。
  • 其他选项
    • O_CREAT :若文件不存在,则创建它。需要使用mode选项(传入3个8进制数字),来指明新文件的访问权限。如果新建的时候,不传入,那对应的文件就是乱码【别忘了实际的权限要考虑umask的影响】
    • O_APPEND:追加写
  • 返回值
    • 成功:新打开的文件的文件描述符(系统通过这个来找到需要访问的文件)
    • 失败:-1

3 读写的系统调用

在这里插入图片描述
write

  • 参数
    • fd:文件描述符
    • buf:指向:要写入的数据,的缓冲区指针
    • count:要写入的字节数
  • 返回
    • 成功:实际写入的字节数
    • 失败:-1,并设置errno
  • 写入类型
    • 对于系统而言,没有什么文本写入和二进制写入(这是语言层的概念)
    • 你传什么指针,他就写什么,如果你原来数据是一个int a,指针传&a,则它就是按二进制写

在这里插入图片描述
readwrite一样,只是这里是读到buf

其余closelseek接口类似C语言

使用示例

以写入为例:

 45 int main()46 {47     int fd = open("log.txt", O_WRONLY | O_CREAT | O_APPEND, 0666); // 这个打开的效果就相当于 C 语言库函数的直接 mode 为 a48     const char* str = (char*)"hello world!\n";49     write(fd, str, strlen(str)); // 不写入 '\0'50     char fd_str[20];51     sprintf(fd_str, "%d\n", fd);  // 转换为文本52     write(fd, fd_str, strlen(fd_str));53     close(fd);54     return 0;55 } 

通常如果是read,则open就是用带两个参数的

运行结果:
在这里插入图片描述

库函数和系统调用

  • C语言的库函数fwritefread其实都是对底层系统调用writeread的封装,在上层为用户提供便利。
  • C语言的库函数具有可移植性,但是系统调用没有
    • 系统调用,如:Linux 的,用的是Linux这一套的。如果把代码移植到Windows或者其他操作系统就不行了
    • C语言,C的fwritefread是对系统调用的封装,但是它不只封装一份操作系统的,它会实现多个操作系统的。后续根据自己在哪个操作系统上使用,通过条件编译(裁剪),来调用对应的系统接口

4 文件描述符(重点)

什么是文件描述符?
如上图所展示的 3 就新打开的log.txt的文件描述符
0, 1, 2分别对应 stdin, stdout, stderr

那系统是如何通过文件描述符来找到要访问的文件的呢?
在这里插入图片描述

  • 在进程的task_struct里面有一个files指针,指向文件描述表files_struct
  • 在文件描述表中,有fd_array[]指针数组,数组的下标对应着文件描述符,指向对应的文件
  • 而每个文件被描述成一个结构体struct file(类似C语言的FILE),里面存储着文件的信息

有了文件描述符fd,进程就会在自己的文件描述表里面找对应下标的文件指针,然后就可以访问对应的文件了。

在这里插入图片描述

文件描述符的分配原则

files_struct数组当中,找到当前没有被使用的最小的⼀个下标,作为新的⽂件描述符。
比如,一开始有0, 1, 2

  • 直接创建一个新文件,则新文件fd == 3
  • close(1),再创建新文件,则fd == 1

注意:这里的关闭不是真关闭,只是“引用计数 - 1”。

  • 因为一个文件可以同时被多个进程访问
  • 同一个文件也可以被同一个进程的多个下标指针同时指向。比如stdoutstderr其实都是向显示器输出

🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!

http://www.xdnf.cn/news/5157.html

相关文章:

  • Satori:元动作 + 内建搜索机制,实现超级推理能力
  • Proser:在使用中改进
  • 使用FastAPI和React以及MongoDB构建全栈Web应用02 前言
  • 什么是向量数据库?向量数据库和关系数据库有什么区别?
  • Java常用类概述
  • C语言_函数hook_LD_PRELOAD原理和示例
  • 阿里云购买ECS 安装redis mysql nginx jdk 部署jar 部署web
  • Docker磁盘空间不足问题
  • 【算法-哈希表】常见算法题的哈希表套路拆解
  • QMK自定义4*4键盘固件创建教程:最新架构详解
  • 《解锁React Native与Flutter:社交应用启动速度优化秘籍》
  • VSCode-插件:codegeex:ai coding assistant / 清华智普 AI 插件
  • Linux:进程间通信---消息队列信号量
  • jMeter压测环境部署JDK+Groovy+JMeter+Proto+IntelliJ IDEA
  • Ubuntu 安装 HAProxy
  • 从代码学习深度学习 - 语义分割和数据集 PyTorch版
  • 图像处理篇---MJPEG视频流处理
  • .Net HttpClient 管理客户端(初始化与生命周期管理)
  • Level1.5算数运算符与赋值运算符
  • Python----神经网络(《Deep Residual Learning for Image Recognition》论文和ResNet网络结构)
  • 内网穿透系列三:开源本地服务公网映射工具 tunnelmole
  • 订单重复扣款故障分析:如何保障支付系统的幂等性
  • kotlin flow防抖
  • 【BYD_DM-i技术解析】
  • cv_area_center()
  • 软考 系统架构设计师系列知识点之杂项集萃(55)
  • OpenVLA:开源的视觉-语言-动作模型
  • 【生命周期分析(Life Cycle Assessment: LCA)】基于OpenLCA、GREET、R语言的生命周期评价方法、模型构建及典型案例应用
  • OC语言学习——Foundation框架(上)
  • 【SpringBoot】从环境准备到创建SpringBoot项目的全面解析.