【Linux】文件周边001之系统文件IO

👀樊梓慕:个人主页

 🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C++》《Linux》《算法》

🌝每一个不曾起舞的日子,都是对生命的辜负


目录

前言

1.C语言文件IO

1.1C语言文件IO接口汇总 

1.2当前路径指的是什么?

 1.3stdin、stdout、stderr

2.系统文件IO

2.1open

参数const char* pathname

参数int flags

*位图方式传参

参数mode_t mode

返回值int fd『 简要理解文件描述符』

2.2close

2.3write 

2.4read


前言

进程周边的相关内容暂时告一段落,下面我们开始学习文件部分。

学习『 系统文件IO』之前,我会与大家先复习一下C语言部分文件IO的相关接口,为后面的学习作『 铺垫』。系统文件IO部分,本篇文章会讲解『 基本的系统调用』:open()、close()、read()、write(),有关参数传递涉及到『 位图方式传递』,这部分以前没有学习过,博主也会拿出来简单的学习一下。


欢迎大家📂收藏📂以便未来做题时可以快速找到思路,巧妙的方法可以事半功倍。

=========================================================================

GITEE相关代码:🌟fanfei_c的仓库🌟

=========================================================================


1.C语言文件IO

1.1C语言文件IO接口汇总 

在学习C语言期间,我们学习过一些C语言封装的文件接口:

C语言文件接口汇总
打开文件
关闭文件
写入一个字符
读取一个字符
写入一个字符串
读取一个字符串
格式化写入数据
格式化读取数据
向二进制文件写入数据
从二进制文件读取数据
设置文件指针的位置
计算当前文件指针相对于起始位置的偏移量
设置文件指针到文件的起始位置
判断文件操作过程中是否发生错误
判断文件指针是否读取到文件末尾

本篇文章不会完全的讲解以上C语言文件接口,想要详细了解的同学可以『 点击以下内容』跳转到博主的有关C语言文件IO的博客。

『 樊梓慕』文件操作——CSDNicon-default.png?t=N7T8http://t.csdnimg.cn/DRPJb

1.2当前路径指的是什么?

当我们利用C语言IO接口创建文件时,生成的文件默认在『 当前路径』,可当前路径具体指的是谁的路径呢?

  • 『 文件是由进程创建』,所以文件的当前路径也是进程的当前路径。

在之前学习进程的部分,我们已经聊过有关话题,当前路径指的是进程在启动时,会保存当前目录的路径,保存到『 /proc/[pid]/cwd』中,该路径就是进程的当前路径。


 1.3stdin、stdout、stderr

在之前学习时,我们提到过一个概念:『 Linux下一切皆文件』 ,也就是说键盘、显示器都是文件,这很好理解,我们向普通文件写入,本质上就是向磁盘写入数据,那将对象改为显示器,是不是就是打印了?

但是,向文件写入我们一般这么操作:

FILE* fp = fopen("log.txt", "w");
fputs("hello world\n", fp);

可是打印我们从未『 打开』显示器文件,也从未『 传递』过流参数:

printf("hello world\n");

这也就说明了:

进程在运行的时候都会『 默认打开』三个输入输出流,即标准输入流、标准输出流以及标准错误流,对应到C语言当中就是stdin、stdout以及stderr。

其中,标准输入流对应的设备就是键盘,标准输出流和标准错误流对应的设备都是显示器。

所以,我们想要实现打印的功能,也可以这样写:

fputs("hello world\n", stdout);

stdin、stdout以及stderr是C标准库下的标准输入输出错误流,其他语言如C++也有对应的标准输入输出错误流:cin、cout和cerr。


2.系统文件IO

 C程序可以直接对硬件进行写入么?

在之前学习的时候,关于操作系统我们有过这样一张图:

什么意思?

程序不可能也不可以越过操作系统直接操作硬件,还记得『 系统调用』么?

 也就是说C标准库中的文件IO接口一定『 封装了系统调用』,所以才能利用fopen()、fputs()等函数对文件进行操作。

那接下来我们就来学习文件IO的系统调用。

2.1open

 open是打开文件的系统调用接口。

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

参数const char* pathname

代表要打开或创建的目标文件。 

  • 若pathname以路径的方式给出,则当需要创建该文件时,就在pathname路径下进行创建。
  • 若pathname以文件名的方式给出,则当需要创建该文件时,默认在当前路径下进行创建。

参数int flags

代表文件的打开方式。

参数含义
O_RDONLY以只读的方式打开文件
O_WRNOLY以只写的方式打开文件
O_APPEND以追加的方式打开文件
O_RDWR以读写的方式打开文件
O_CREAT当目标文件不存在时,创建文件

传递方式介绍:

例如:以只写的方式打开文件,当目标文件不存在时自动创建文件,则参数设置如下:

O_WRONLY | O_CREAT

为什么这么传递??

*位图方式传参

 先写一段代码:

#define ONE 1
#define TWO (1<<1)
#define THREE (1<<2)
#define FOUR (1<<3)
#define FIVE (1<<4)void Print(int flag)
{if(flag & ONE) printf("1\n");if(flag & TWO) printf("2\n");if(flag & THREE) printf("3\n");if(flag & FOUR) printf("4\n");if(flag & FIVE) printf("5\n");
}int main()
{Print(ONE);printf("----------------------\n");Print(TWO);printf("----------------------\n");Print(ONE|TWO);printf("----------------------\n");Print(THREE|FOUR|FIVE);printf("----------------------\n");Print(ONE|TWO|THREE|FOUR|FIVE);
}

 根据代码中的宏定义,这些宏的特点就是所有位加起来只有一个1。 

 Print函数中五个if中的判断条件其实就是判断参数哪个位为1,如果传的是ONE,那么ONE与ONE&得到的就是1,为真就打印1,其余的都为假,不打印。

当带上|操作符后,相当于把两个参数的1位合并到一起,比如ONE|TWO得到的就是0011,所以在Print中就会满足两个条件flag & ONE 和 flag & TWO。

这就是位图方式传参的基本思想。


放到flags中呢?

#define O_RDONLY       0000
#define O_WRONLY       0001
#define O_RDWR         0010
#define O_CREAT        0100

之后通过&运算:

int open(arg1, arg2, arg3){if (arg2&O_RDONLY){//设置了O_RDONLY选项}if (arg2&O_WRONLY){//设置了O_WRONLY选项}if (arg2&O_RDWR){//设置了O_RDWR选项}if (arg2&O_CREAT){//设置了O_CREAT选项}//...
}

所以如果arg2=O_CREAT | O_WRONLY,即arg2=0101,arg2 & O_WRONLY =1 && arg2 & O_CREAT =1就达到了『 以只写的方式打开文件,当目标文件不存在时自动创建文件』的目的。

这就是『 位图方式传参』。

参数mode_t mode

代表创建文件的默认权限。

例如:将mode设置为0666,则创建出来的文件权限如下:

-rw-rw-rw-

但『 实际上』创建出来文件的权限值还会受到umask(文件默认掩码)的影响。

实际创建出来文件的权限为:mode减去对应位的umask值。

umask的默认值默认为0002,所以当我们设置mode值为0666时实际创建出来文件的权限为0664。

若想创建出来文件的权限值不受umask的影响,则需要在创建文件前使用umask函数将文件默认掩码设置为0。

umask(0); //将文件默认掩码设置为0

如果不需要创建新的文件,则使用两个参数的open即可。 

返回值int fd『 简要理解文件描述符』

代表打开文件的『 文件描述符』。

  • fd>0:返回的是文件描述符。
  • fd==-1:代表打开文件失败。

一个进程可以打开多个文件:        

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main()
{umask(0);int fd1 = open("log1.txt", O_RDONLY | O_CREAT, 0666);int fd2 = open("log2.txt", O_RDONLY | O_CREAT, 0666);int fd3 = open("log3.txt", O_RDONLY | O_CREAT, 0666);int fd4 = open("log4.txt", O_RDONLY | O_CREAT, 0666);int fd5 = open("log5.txt", O_RDONLY | O_CREAT, 0666);printf("fd1:%d\n", fd1);printf("fd2:%d\n", fd2);printf("fd3:%d\n", fd3);printf("fd4:%d\n", fd4);printf("fd5:%d\n", fd5);return 0;
}

 为什么是从3开始呢?

我们刚才讲进程默认会打开三个输入输出流:标准输入流、标准输出流、标准错误流。

所以0、1、2分别代表了它们。

从而我们得到文件描述符的分配规则:

找到当前没有被使用的最小的下标,作为新的文件描述符。 


2.2close

close是关闭文件的系统调用接口。

int close(int fd);//参数fd是文件描述符
  • 关闭文件成功返回0;
  • 关闭文件失败返回-1。

2.3write 

write是写入文件的系统调用接口。

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

功能:将buf位置开始向后count字节的数据写入文件描述符为fd的文件当中。

  • 写入成功,返回写入数据的字节个数。
  • 写入失败,返回-1。

例如: 

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);if (fd < 0){perror("open");return 1;}const char* msg = "hello syscall\n";for (int i = 0; i < 5; i++){write(fd, msg, strlen(msg));}close(fd);return 0;
}

2.4read

read是读取文件的系统调用接口。

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

功能:从文件描述符为fd的文件读取count字节的数据到buf位置当中。

  • 读取成功,返回读取数据的字节个数。
  • 读取失败,返回-1。

例如:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{int fd = open("log.txt", O_RDONLY);if (fd < 0){perror("open");return 1;}char ch;while (1){ssize_t s = read(fd, &ch, 1);if (s <= 0){break;}write(1, &ch, 1); //向文件描述符为1的文件写入数据,即向标准输出流(显示器)写入数据}close(fd);return 0;
}

当然对于文件管理来说还有很多需要讲解的细节,博主会放到下一篇文章中详细讲解,下一篇文章会深入学习『 Linux系统是如何管理文件的』,『 文件描述符在其中又扮演了怎样的角色』,『 怎么理解Linux下一切皆文件』等等内容,本篇文章只是文件部分的简单开头,主要目的是为了『 作铺垫』,更多内容,请持续关注博主Linux系列文章。 

=========================================================================

如果你对该系列文章有兴趣的话,欢迎持续关注博主动态,博主会持续输出优质内容

🍎博主很需要大家的支持,你的支持是我创作的不竭动力🍎

🌟~ 点赞收藏+关注 ~🌟

=========================================================================

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024 V加爆好友的4个方法

2024加好友&#x1f449;加爆V信的4个方法

SUSE Linux 15 SP5 安装图解

风险告知 本人及本篇博文不为任何人及任何行为的任何风险承担责任&#xff0c;图解仅供参考&#xff0c;请悉知&#xff01;本次安装图解是在一个全新的演示环境下进行的&#xff0c;演示环境中没有任何有价值的数据&#xff0c;但这并不代表摆在你面前的环境也是如此。生产环境…

如何自己制作一个属于自己的小程序?

在这个数字化时代&#xff0c;小程序已经成为了我们生活中不可或缺的一部分。它们方便快捷&#xff0c;无需下载安装&#xff0c;扫一扫就能使用。如果你想拥有一个属于自己的小程序&#xff0c;不论是为了个人兴趣&#xff0c;还是商业用途&#xff0c;都可以通过编程或者使用…

【论文阅读|2024 WACV 多目标跟踪Deep-EloU】

论文阅读|2024 WACV 多目标跟踪Deep-EloU 摘要1 引言&#xff08;Introduction&#xff09;2 相关工作&#xff08;Related Work&#xff09;2.1 基于卡尔曼滤波器的多目标跟踪算法&#xff08;Multi-Object Tracking using Kalman Filter&#xff09;2.2 基于定位的多目标跟踪…

一篇博客读懂排序

目录 一、常见的排序 二、冒泡排序 2.1基本思想&#xff1a; 2.2代码&#xff1a; 三、插入排序 3.1基本思想&#xff1a; 3.2思路讲解&#xff1a; 3.3代码&#xff1a; 3.4时间复杂度&#xff1a; 四、希尔排序 4.1基本思路&#xff1a; 4.2思路讲解&#xff1a;…

微信小程序如何获取当前日期时间

Hello大家好&#xff01;我是咕噜铁蛋&#xff0c;获取当前日期时间是小程序中经常会用到的一个功能。因此&#xff0c;在本文中&#xff0c;我通过科技手段给大家收集整理了下&#xff0c;今天我将向大家介绍如何在微信小程序中获取当前日期时间的方法&#xff0c;并分享一些实…

Overleaf(LaTeX文档在线编写平台)使用学习记录

一、LaTeX简概[1] LaTeX&#xff0c;是一种基于TEX的排版系统&#xff0c;是一种可以处理排版和渲染的标记语言。由美国计算机科学家莱斯利兰伯特在20世纪80年代初期开发&#xff0c;利用这种格式系统的处理&#xff0c;即使用户没有排版和程序设计的知识也可以充分发挥由TEX所…

离零售业智能体时代的真正开启还有多远?

AIGC&#xff08;生成式人工智能&#xff09;当道的2023年&#xff0c;将LLM&#xff08;大语言模型&#xff09;的各类生成式能力发挥到淋漓尽致、精彩纷呈的程度。各行各业一边在观望大语言模型不断扩宽的商业运用可能&#xff0c;一边在继续探寻能够不断拓宽企业往纵深发展的…

Mybatis----缓存

MyBatis是一个流行的Java持久化框架&#xff0c;它提供了一个灵活的缓存机制来提高查询性能。 MyBatis的缓存机制主要分为一级缓存和二级缓存。 一级缓存是指在同一个SqlSession中&#xff0c;查询结果会被缓存起来&#xff0c;当再次执行同样的查询时&#xff0c;直接从缓存中…

基于SSM的企业文档管理系统

末尾获取源码作者介绍&#xff1a;大家好&#xff0c;我是何时&#xff0c;本人4年开发经验&#xff0c;专注定制项目开发 更多项目&#xff1a;CSDN主页YAML 我欲乘风归去 又恐琼楼玉宇 高处不胜寒 -苏轼 一、项目简介 现代经济快节奏发展以及不断完善升级的信息化技术&…

深度了解TCP/IP模型

网络通信是现代社会不可或缺的一部分&#xff0c;而TCP/IP模型作为网络通信的基石&#xff0c;扮演着至关重要的角色。本文将深入探讨TCP/IP模型的概念、结构及其在网络通信中的作用&#xff0c;为读者提供全面的了解。 一.TCP/IP模型简介 TCP/IP模型是一个网络通信协议体系&a…

机器学习 | 掌握Matplotlib的可视化图表操作

Matplotlib是python的一个数据可视化库&#xff0c;用于创建静态、动态和交互式图表。它可以制作多种类型的图表&#xff0c;如折线图、散点图、柱状图、饼图、直方图、3D 图形等。以渐进、交互式方式实现数据可视化。当然博主也不能面面俱到的讲解到所有内容&#xff0c;详情请…

【极数系列】Flink 初相识(01)

# 【极数系列】Flink 初相识&#xff08;01&#xff09; 引言 Flink官网&#xff1a;https://flink.apache.org/ Flink版本&#xff1a;https://flink.apache.org/blog/ Flink文档&#xff1a;https://ci.apache.org/projects/flink/flink-docs-release-1.12/ Flink代码库…

轻松互换文件夹名,高效批量改名!高手工具助您一臂之力!

在日常工作中&#xff0c;我们经常需要处理大量的文件夹&#xff0c;有时候需要将文件夹名称互换或进行批量改名。这时&#xff0c;一款高效、实用的高手工具就能派上用场。它不仅能帮助您轻松实现文件夹名互换&#xff0c;还能快速批量改名&#xff0c;让您的工作更加高效、轻…

Unity - 角色控制

Test_05 角色控制 创建一个3D对象作为角色&#xff0c;添加 “CharacterController” 组件来控制角色移动&#xff0c;绑定脚本"PlayerControl"。 PlayerControl public class PlayerControl : MonoBehaviour {private CharacterController player;void Start(){p…

RabbitMQ系列之入门级

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是君易--鑨&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《RabbitMQ系列之入门级》。&#x1f3af;&#x…

防火墙基础1

防火墙简绍 什么是防火墙? 状态防火墙工作原理? 防火墙如何处理双通道协议? 防火墙如何处理nat? 路由交换终归结底是连通性设备。 网络在远古时期没有防火墙大家都是联通的&#xff0c;any to any。 防御对象&#xff1a; 授权用户 非授权用户 防火墙是一种隔离…

存储开发入门到进阶,这几本书一定要看!!

有些朋友是已经深耕存储多年&#xff0c;有的朋友是刚刚入门、或者说有兴趣但是迟迟不得入门。以下从笔者的经验出发&#xff0c;向大家推荐几本书&#xff0c;可以比较系统的补充一些编程的内功和存储的基础知识&#xff0c;向你展示一条存储通关之路。 语言 语言是第一个要…

55. 跳跃游戏 - 力扣(LeetCode)

题目描述 给定一个非负整数数组&#xff0c;你最初位于数组的第一个位置。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个位置。 题目示例 输入&#xff1a;nums [2,3,1,1,4] 输出&#xff1a;true 解释&#xff1a;可以先跳 1 步&#x…

LFU算法

LFU算法 Least Frequently Used&#xff08;最不频繁使用&#xff09; Leetcode有原题&#xff0c;之前手写过LRU&#xff0c;数据结构还是习惯于用java实现&#xff0c;实现是copy的评论题解。 题解注释写的很清楚 大致就是说LFUCache类维护一个存放node的map&#xff0c;同…