基础I/O--文件系统

在这里插入图片描述

文章目录

  • 回顾C文件接口
  • 初步理解文件
  • 理解文件
    • 使用和并认识系统调用
      • open
        • 概述
        • 标记位传参理解
        • 返回值
      • close
      • write
      • read
      • 总结
    • 文件描述符fd
      • 0&1&2
      • 理解

回顾C文件接口

C代码:

#include<stdio.h>    
    
int main()    
{    
  FILE *fp=fopen("log.txt","w");    
  if(NULL==fp)    
  {    
    perror("fopen");    
    return 1;    
  }    
    
  fclose(fp);                                                                                                                            
  return 0;    
}  

我们要进行文件操作,前提是程序运行起来了,所谓的文件的打开和关闭是CPU执行我们的代码才被打开或者关闭的。
fopen()函数:
在这里插入图片描述

初步理解文件

打开文件:本质上是进程打开文件

文件没有被打开的时候,在哪里?在磁盘上

一个进程能打开很多文件吗? 可以

系统中可不可以存在很多进程? 可以

因此,在很对情况下,操作系统内部一定存在大量的被打开的文件
操作系统要不要对这些被打开的文件进行管理? 要
如何管理?先描述,再组织

如果在磁盘新建一个文件,里面什么内容都没有,大小为0KB,那么这个文件占用空间吗?占,因为文件对应的创建时间、文件类型等对应的文件属性都存在。
因此,文件=内容+属性

理解文件

操作文件,本质上是进程在操作文件

文件没有被打开时,文件在磁盘上,磁盘属于外部设备,磁盘本质是一个硬件,向文件写入,本质是向硬件中写入,但是用户没有权利直接向硬件写入,硬件的管理者是操系统,因此用户不能绕过操作系统直接访问硬件,必须通过操作系统写入。操作系统给用户提供系统调用,我们用的C/C++/其他语言,都是对系统调用接口的封装。
访问文件除了可以使用已经封装好的函数,还可以使用系统调用。

在这里插入图片描述

使用和并认识系统调用

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, mode_t mode);

int creat(const char *pathname, mode_t mode);

pathname: 要打开或创建的目标文件
flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。
参数:
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读,写打开
这三个常量,必须指定一个且只能指定一个
O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND: 追加写
返回值:
成功:新打开的文件描述符
失败:-1

open 函数具体使用哪个,和具体应用场景相关,如目标文件不存在,需要open创建,则第三个参数表示创建文件的默认权限,否则,使用两个参数的open。

标记位传参理解
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

int main()
{
  umask(0);
  //system call
  int fd=open("log.txt",O_WRONLY|O_CREAT,0666);
  if(fd<0)
  {
    perror("open");
    return 1;
  }
}

在这里插入图片描述

操作系统本身就有一个权限掩码,现在在代码中又写了一个权限掩码。这里使用的是代码中的掩码,就近原则。自己设置了权限掩码就用自己设置的,没有就用系统的。因此最终创建的权限掩码就是666


int flag:是32个比特位的,用比特位来进行标志位的传递。flag标志位传递本质上是一个位图。

我们来设计一个传递为图标记位的函数:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

#define ONE 1            //1: 0000 0001
#define TWO (1<<1)       //2: 0000 0010
#define THREE (1<<2)     //3: 0000 0100
#define FOUR (1<<3)      //4: 0000 1000

void print(int flag)
{
  if(flag&ONE) printf("one\n");
  if(flag&TWO) printf("two\n");
  if(flag&THREE) printf("three\n");
  if(flag&FOUR) printf("four\n");
} 

int main()
{
  print(ONE);
  printf("\n");

  print(TWO);
  printf("\n");

  print(ONE|TWO);
  printf("\n");

  print(ONE|TWO|THREE);
  printf("\n");

  print(ONE|FOUR);
  printf("\n");

  return 0;
}

在这里插入图片描述

如果我们将打印替换成其他功能,那么就可以写出一个向指定函数传递标记位的方法。

返回值
RETURN VALUE
open() and creat() return the new file descriptor, or -1 if an error occurred (in which case, errno is set appropriately).

在这里插入图片描述
返回成功,就帮我们创建一个新的文件描述符,就是一个整数,失败返回-1

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>

int main()
{
  int fda=open("loga.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
  printf("fda:%d\n",fda);

  int fdb=open("logb.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
  printf("fdb:%d\n",fdb);

  int fdc=open("logc.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
  printf("fdc:%d\n",fdc);

  int fdd=open("logd.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
  printf("fdd:%d\n",fdd);

  return 0;
  
}

运行结果:

在这里插入图片描述

返回值是3 4 5 6,怎么不见0 1 2呢?
因为 0 1 2分别对应标准输入(键盘)、标准输出(显示器)、标准错误(显示器)

下文有具体介绍

close

在这里插入图片描述

#include <unistd.h>

int close(int fd);

write

man 2 write可查看write函数
在这里插入图片描述

第一个参数 fd:表示待写入文件的文件描述符。

第二个参数 buf:指向待写入的文件内容。

第三个参数 count:待写入内容的大小,单位是字节。

返回值:实际上写入的字节数。

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
int main()
{
  umask(0);
  //system call
  int fd=open("log.txt",O_WRONLY|O_CREAT,0666);
  if(fd<0)
  {
    perror("open");
    return 1;
  }

  const char *message="hello linux file!\n";
  write(fd,message,strlen(message));

  close(fd);
  return 0;
}

在这里插入图片描述

会发现确实是写入了hello linux file!

将上述代码中,写入hello linux file!,修改成aaa

  const char *message="aaa";
  write(fd,message,strlen(message));

运行结果:

在这里插入图片描述

可见,默认不清空文件

那么,如何再次写入文件时,之前文件会被清空呢?
需要添加一个O_TRUNC

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
int main()
{
  umask(0);
  //system call
  int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
  if(fd<0)
  {
    perror("open");
    return 1;
  }

  const char *message="aaa";
  write(fd,message,strlen(message));

  close(fd);
  return 0;
}

在这里插入图片描述

运行结果:

在这里插入图片描述


追加写入:

int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);

在这里插入图片描述

read

#include <unistd.h>

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

第一个参数 fd:要读取文件的文件描述符。

第二个参数 buf:指向一段空间,该空间用来存储读取到的内容。

第三个参数 count:参数二指向空间的大小。

总结

intfd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);

写方式打开,不存在就创建,存在就先清空


int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);

追加形式写入

文件描述符fd

0&1&2

  • Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2.
  • 0,1,2对应的物理设备一般是:键盘,显示器,显示器

理解

在一个操作系统中有很多文件,操作系统需要对被打开文件进行管理,也就是需要创建对应的数据结构(struct_file),对文件的管理转换成对链表的增删查改。
任何一个文件=内容+属性,磁盘中文件的属性来初始化struct_file,将文件内容写入文件内核缓存里。

一个进程可以打开多个文件,对于进程来说怎么知道被打开文件与自己有关系,因此对应的task_struct存在一个属性struct files_struct *files,指向该类型的一个对象,该类型对象记录了当前进程所打开的所有文件新信息,操作系统中就存在一个结构体:struct file_struct,里面存在一个指针数组,数组的内容指向当前进程所打开的文件结构对象,也就是指向当前进程打开的文件。我们称这个数组为文件描述符表,数组下标称为文件描述符

文件描述符fd的本质是什么?
内核进程:文件映射关系的数组下标。

在这里插入图片描述

无论读写,都必须在合适的时候,让操作系统把文件内容读到文件缓冲区中。

open在干什么??

  1. 创建file
  2. 开辟文件缓冲区的空间,加载文件数据(延后)
  3. 查进程的文件描述符表
  4. file地址填入对应的下标中
  5. 返回下标

读写函数本质是拷贝函数

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/593465.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

08 - 步骤 表输出

简介 表输出&#xff08;Table Output&#xff09;步骤是用于将 Kettle 中的数据写入关系型数据库表的步骤。它允许用户将数据流中的数据插入、更新或删除到目标数据库表中。 使用 场景 我要将处理完的数据流中的sysOrgCode 跟 plateNumber 保存记录到mysql 1、拖拽表输出…

2.VAM新建保存修改场景文件

新建场景 点击返回场景预览 打开游戏的时候&#xff0c;本身就有了一个新场景&#xff0c;因为现在场景里什么也没有&#xff0c;所以是一片黑暗 点击星号打开主菜单会返回主界面 做一个最简单的Helloworld场景 底下有两个模式&#xff0c;游玩模式和编辑模式 编辑场景的时候…

OpenCV如何使用 GDAL 读取地理空间栅格文件(72)

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇:OpenCV的周期性噪声去除滤波器(70) 下一篇 :OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 目录 目标 代码&#xff1a; 解释&#xff1a; 如何使用 GDAL 读取栅格数据 注意 …

05_G1垃圾收集器

G1垃圾收集器简介 垃圾优先 Garbage-First&#xff08;G1&#xff09;垃圾收集器面向多处理器机器&#xff0c;适用于大内存场景。它尝试在无需太多配置的情况下实现垃圾收集暂停时间目标&#xff0c;并同时实现高吞吐量。G1旨在通过适用于当前目标应用和环境的功能&#xff0…

go mod

常用命令 初始化模块 go mod init 模块名下载 go.mod 文件中指明的所有依赖 go mod download github.com/gin-gonic/ginv1.9.(依赖路径)依赖对其&#xff08;使引用的都是所依赖的&#xff09; go mod tidy编辑go.mod go mod edit go mod edit -require"github.com/g…

记录几种排序算法

十种常见排序算法可以分类两大类别&#xff1a;比较类排序和非比较类排序。 常见的快速排序、归并排序、堆排序以及冒泡排序等都属于比较类排序算法。比较类排序是通过比较来决定元素间的相对次序&#xff0c;其时间复杂度不能突破 O(nlogn)。在冒泡排序之类的排序中&…

数据结构---时间复杂度+空间复杂度

算法(algorithm)简单说就是解决问题的方法。方法有好坏&#xff0c;同样算法也是&#xff0c;有效率高的算法&#xff0c;也有效率低的算法。衡量算法的好坏一般从时间和空间两个维度衡量&#xff0c;也就是本文要介绍的时间复杂度和空间复杂度。有些时候&#xff0c;时间与空间…

js api part3

环境对象 环境对象&#xff1a; 指的是函数内部特殊的 变量 this &#xff0c; 它代表着当前函数运行时所处的环境 作用&#xff1a; 弄清楚this的指向&#xff0c;可以让我们代码更简洁 函数的调用方式不同&#xff0c;this 指代的对象也不同 【谁调用&#xff0c; this 就是…

springboot模块以及非springboot模块构成的多模块maven项目最佳构建方式

文章目录 背景一般的实现使用spring-boot-dependencies 更优雅的实现. 背景 有时候构建一个多模块maven项目其中某一个模块是web-service需要使用spring boot,其他模块跟spring boot 完全无关,本文总结一下在这个场景下maven项目最佳构建方式. 一般的实现 网上应该也看到过很…

智能工业相机哪家好?

一、什么是智能工业相机 在工业自动化的浪潮中&#xff0c;智能工业相机扮演着至关重要的角色。它们如同工业领域的“眼睛”&#xff0c;为生产过程提供精准的视觉监测和数据采集。然而&#xff0c;面对众多的智能工业相机品牌&#xff0c;如何选择一款真正适合的产品成为了众多…

企业开发基础--数据库

今天完成了数据库学习的全部内容&#xff0c;在事务&#xff0c;索引&#xff0c;范式中要有个人逻辑上的理解&#xff0c;也算是卡着点完成了大多数预期&#xff0c;还有一个Java游戏未完成&#xff0c;会后续补上。 之后的一周要完成34道数据库练习题以及JDBC&#xff0c;学…

88、动态规划-乘积最大子数组

思路&#xff1a; 首先使用递归来解&#xff0c;从0开始到N&#xff0c;每次都从index开始到N的求出最大值。然后再次递归index1到N的最大值&#xff0c;再求max。代码如下&#xff1a; // 方法一&#xff1a;使用递归方式找出最大乘积public static int maxProduct(int[] num…

Graph RAG:基于知识图谱的检索增强技术与优势对比

身处信息爆炸时代&#xff0c;如何从海量信息中获取准确全面的搜索结果&#xff0c;并以更直观、可读的方式呈现出来是大家期待达成的目标。传统的搜索增强技术受限于训练文本数量、质量等问题&#xff0c;对于复杂或多义词查询效果不佳&#xff0c;更无法满足 ChatGPT 等大语言…

【Linux】进程间通信 - 管道

文章目录 1. 进程间通信介绍1.1 进程间通信目的1.2 进程间通信发展1.3 进程间通信分类 2. 管道2.1 什么是管道2.2 匿名管道2.3 用 fork 来共享管道原理2.4 站在文件描述符角度 - 深入理解管道2.5 站在内核角度 - 管道本质2.6 管道读写规则2.7 管道特点 3. 命名管道3.1 匿名管道…

C语言实战项目--贪吃蛇

贪吃蛇是久负盛名的游戏之一&#xff0c;它也和俄罗斯⽅块&#xff0c;扫雷等游戏位列经典游戏的行列。在编程语言的教学中&#xff0c;我们以贪吃蛇为例&#xff0c;从设计到代码实现来提升大家的编程能⼒和逻辑能⼒。 在本篇讲解中&#xff0c;我们会看到很多陌生的知识&…

牛角源码 | 【独立版】商城盲盒源码带uniapp(H5+小程序+APP三端)全开源

前端uniapp开源代码&#xff0c;可用HBuilder工具无限发行H5、小程序和打包app&#xff0c;后端PHP开源源码&#xff0c;支持二开。 内有安装搭建教程&#xff0c;轻松部署&#xff0c;搭建即可运营&#xff0c;内置永久免费更新地址&#xff0c;后续无忧升级。 下载地址&…

window 安装ai 基础环境(yolo8,训练推理等)

安装步骤: 1. python sdk 3.9以上&#xff1a;选择 3.9.13, 不知道为什么 3.9.0-0a等安装pytorch 不行。 2. 显卡驱动 可以使用驱动精灵 直接安装N 卡推荐 3. 安装机器学习套件CUDA cuda 安装在PyTorch 需要根 PyTorch版本一致&#xff0c;我的 win-srv 最高支持 12.1 …

专业渗透测试 Phpsploit-Framework(PSF)框架软件小白入门教程(五)

本系列课程&#xff0c;将重点讲解Phpsploit-Framework框架软件的基础使用&#xff01; 本文章仅提供学习&#xff0c;切勿将其用于不法手段&#xff01; 继续接上一篇文章内容&#xff0c;讲述如何进行Phpsploit-Framework软件的基础使用和二次开发。 在下面的图片中&#…

星辰考古:TiDB v1.0 再回首

“ 1.0 版本只是个开始&#xff0c;是新的起点&#xff0c;愿我们一路相扶&#xff0c;不负远途。 前言 TiDB 是 PingCAP 公司自主设计、研发的开源分布式关系型数据库。 近日&#xff0c;TiDB v8.0.0 DMR 发布&#xff0c;详细发版说明戳这里&#xff1a; https://docs.pingca…

2024年Q1季度防晒霜数据分析:个性化与差异化成为破局关键

五一出游期间&#xff0c;防晒必不可少&#xff0c;尤其是随着“颜值经济”的崛起&#xff0c;防晒霜成为了许多消费者出游时的必备选择。但随着“物理防晒”、“硬防晒”等概念的推出&#xff0c;防晒霜作为“化学防晒”的代表&#xff0c;在今年Q1季度线上市场表现受到影响。…
最新文章