[Linux]:文件(上)
✨✨ 欢迎大家来到贝蒂大讲堂✨✨
🎈🎈养成好习惯,先赞后看哦~🎈🎈
所属专栏:Linux学习
贝蒂的主页:Betty’s blog
1. C语言文件操作
C语言文件操作接口如下,详情可参照——C语言文件
文件操作函数 | 功能 |
---|---|
fopen | 打开文件 |
fclose | 关闭文件 |
fputc | 写入一个字符 |
fgetc | 读取一个字符 |
fputs | 写入一个字符串 |
fgets | 读取一个字符串 |
fprintf | 格式化写入数据 |
fscanf | 格式化读取数据 |
fwrite | 向二进制文件写入数据 |
fread | 从二进制文件读取数据 |
fseek | 设置文件指针的位置 |
ftell | 计算当前文件指针相对于起始位置的偏移量 |
rewind | 设置文件指针到文件的起始位置 |
ferror | 判断文件操作过程中是否发生错误 |
feof | 判断文件指针是否读取到文件末尾 |
读写方式如下:
文件使用方式 | 含义 | 如果指定文件不存在 |
---|---|---|
“r”(只读) | 为了输入数据,打开一个已经存在的文本文件 | 出错 |
“w”(只写) | 为了输出数据,打开一个文本文件 | 建立一个新的文件 |
“a”(追加) | 向文本文件尾添加数据 | 出错 |
“rb”(只读) | 为了输入数据,打开一个二进制文件 | 出错 |
“wb”(只写) | 为了输出数据,打开一个二进制文件 | 建立一个新的文件 |
“ab”(追加) | 向一个二进制文件尾添加数据 | 出错 |
“r+”(读写) | 为了读和写,打开一个文本文件 | 出错 |
“w+”(读写) | 为了读和写,建议一个新的文件 | 建立一个新的文件 |
“a+”(读写) | 打开一个文件,在文件尾进行读写 | 建立一个新的文件 |
“rb+”(读写) | 为了读和写打开一个二进制文件 | 出错 |
“wb+”(读写) | 为了读和写,新建一个新的二进制文件 | 建立一个新的文件 |
“ab+”(读写) | 打开一个二进制文件,在文件尾进行读和写 | 建立一个新的文件 |
下面是一个使用C语言文件的示例:
#include<stdio.h>
int main()
{FILE*fp=fopen("log.txt","w");if(fp==NULL){perror("fopen fail:");return 1;}//open successconst char*msg="hello betty!\n";int count=5;while(count--){fputs(msg,fp);}fclose(fp);return 0;
}
一般而言如果没有定义对应的log.txt
文件,系统会在当前路径自动创建该文件。并且当前路径并不是指可执行程序所处的路径,而是指该可执行程序运行成为进程时我们所处的路径。比如我们可以在上级目录执行testfile
文件:
可以看见log.txt
是在该对应路径创建的,而不是对应可执行文件所在目录创建的。
其中我们也可以通过监视进程的方式,观察一下:
然后我们可以看见两个软连接cwd
和exe
,分别对应的就是进程运行时我们所处的路径,以及可执行文件所处路径。
2. 三个默认打开流
我们常说Linux
下一切皆文件,那么我们的键盘与显示器自然也是文件。我们向键盘输入数据,本质就是操作系统向键盘文件中读取数据;我们能从显示器看见数据,本质就是操作系统向显示器文件写入数据。但是我们在使用键盘与显示器时并没有手动进行任何文件相关的读写操作,那我们又是如何对键盘文件与显示器文件进行读写的呢?
答案自然是操作系统自动帮我们打开的,任何进程在运行时,操作系统都会默认打开三个输入输出流,分别为:标准输入流,标准输出流以及标准错误流。对于C语言分别就是:stdin
、stdout
以及stderr
。对于C++分别就是:cin
、cout
和cerr
,自然其他语言也会有相似的概念,因为这是操作系统所支持的,而不是某个语言所独有的。
我们可以在Linux
中的man
查看对应的声明:
其中标准输入流对应的就是我们的键盘,而标准输出流与标准错误流对应的就是我们显示器。
其中我们也可以通过fputs
函数验证一下:
#include<stdio.h>
int main()
{//向显示器打印fputs("hello betty!\n",stdout);fputs("hello betty!\n",stdout);fputs("hello betty!\n",stdout);fputs("hello betty!\n",stdout);return 0;
}
3. 系统文件I/O
在前面我们学习操作系统时知道,为了方便用户使用,一般我们会对系统接口进行封装。我们的文件操作也不例外,像fopen
,fclose
等接口本质其实对操作系统提供的文件接口的封装。接下来我们就来学习一下系统提供的文件接口。
3.1 open函数
首先我们来介绍文件打开操作的系统接口。
pathname
:表示打开或者创建的目标文件,若pathname
以路径的方式给出,则当需要创建该文件时,就在pathname
路径下进行创建。若pathname
以文件名的方式给出,则当需要创建该文件时,默认在当前路径下进行创建。- ·
flags
:表示打开文件的方式。mode
:表示创建文件的默认权限(八进制数)。
其中常用文件打开方式有如下几个:
参数选项 | 含义 |
---|---|
O_RDONLY | 以只读的方式打开文件 |
O_WRNOLY | 以只写的方式打开文件 |
O_APPEND | 以追加的方式打开文件 |
O_RDWR | 以读写的方式打开文件 |
O_CREAT | 当目标文件不存在时,创建文件 |
如果想同时兼具多个打开方式,可以使用逻辑与|
链接两个选项。比如说我们想打开文件并且文件不存在时创建文件,可以写成:
O_WRNOLY|O_CREAT
这些选项本质也就是一个宏定义,其中flags
是一个整型,若将一个比特位作为一个标志位,则理论上flags
可以传递32种不同的标志位。
所以我们也可以使用按位与&
操作来检测是否设置某个选项:
if (flags&O_RDONLY){//设置了O_RDONLY选项
}
if (flags&O_WRONLY){//设置了O_WRONLY选项
}
if (flags&O_RDWR){//设置了O_RDWR选项
}
if (flags&O_CREAT){//设置了O_CREAT选项
}
//...
并且如果我们打开的文件已存在就使用第一个接口(两个参数),如果打开的文件不存在就需要使用第二个接口(三个参数),即需要为创建的文件设置默认权限。
如果我们要为文件设置默认权限,就需要考虑文件默认掩码umask
的影响。我们之前讲过文件的默认权限为:mode&(~mask)
,我们除了可以在命令行通过指令umask 八进制数
来修改默认的掩码umask
(默认为002)外,还能在程序中调用umask
函数进行修改。比如我们将umask
设置为0:
umask(0); //将文件默认掩码设置为0
最后再来探究一下open
的返回值,也就是文件描述符fd
。
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{umask(0);//设置文件掩码为0int 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开始的,并且依次递增,这起始并不是偶然。至于为什么,我们等会儿在揭晓。
当然这只是文件成功返回的情况,如果文件打开失败,那将返回-1。
3.2 close函数
我们可以调用系统接口close
来关闭指定文件,其原型为:
int close(int fd);
使用close
函数时传入需要关闭文件的文件描述符即可,若关闭文件成功则返回0,若关闭文件失败则返回-1。
3.3 write函数
同样我们也能通过系统接口write
对文件进行写入,其原型为:
ssize_t write(int fd, const void *buf, size_t count);
其中fd
指的是文件描述符,buf
为用户缓冲区,而count
为期望写的字节数。如果写入成功返回实际写入的字节数,若写入失败则返回-1。
注意:ssize_t
其实就是一个有符号整型,具体来说就是被typedef
重新定义过:typedef int ssize_t
以下我们可以利用write
函数对一个log.txt
文件进行写入:
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
int main()
{int fd=open("log.txt",O_WRONLY|O_CREAT);if(fd<0){//open errorperror("open fail:");return 1;}const char*msg="hello betty!\n";for(int i=0;i<8;i++){write(fd,msg,strlen(msg));}close(fd);return 0;
}
3.4 read函数
同样我们也能通过系统接口read
对文件进行读写,其原型为:
ssize_t read(int fd, void *buf, size_t count);
其中fd
指的是文件描述符,buf
为用户缓冲区,而count
为期望读的字节数。如果读出成功返回实际读出的字节数,若读出失败则返回-1。
以下我们可以利用read
函数对一个log.txt
文件进行读出:
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
int main()
{int fd=open("log.txt",O_RDONLY);if(fd<0){perror("open fail:");return 1;}char buf[1024]={'\0'};ssize_t ret=read(fd,buf,1023);if(ret>0)printf("%s",buf);close(fd);return 0;
}
4. 文件描述符——fd
在我们的操作系统中,文件是由我们进程所打开的,存在大量进程就意味着存在大量被打开的文件。为了方便我们对文件进行管理,我们就将每个文件struct file
链入我们的双向链表之中。
struct File
{//包含了打开文件的相关属性//链接属性
};
而一个文件也可能被多个进程所读写,为了让操作系统能够准确识别每个进程对应的文件,我们就一定要让进程与我们的文件建立联系。事实也是如此,我们的进程控制块task_struct
中就存在一个指针指向一个名为struct file_struct
的结构体,这个结构体中存在一个结构体指针数组struct file*fd_array[]
分别存放着着每个文件struct file
的地址。这样我们的进程就与文件建立起了联系。
一般我们的指针数组struct file*fd_array[]
的0,1,2下标分别对应我们的标准输入流,标准输出流,标准错误流这三个文件,而这些下标就是我们所说的文件描述符——fd。这也解释了我们打开文件的描述符为什么从3开始,并且依次递增。并且,通过对应的文件描述符,进程只需要找到对应的指针数组fd_array
就能访问对应的文件,这也是为什么我们文件的系统调用接口的参数一定会有fd
的原因。
当然如果我们在中途关掉某个文件,操作系统就会为该下标重新分配对应的文件。
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main()
{close(0);close(2);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;
}
我们也知道,当一个程序运行起来时,操作系统会将该程序的代码和数据加载到内存,然后为其创建对应的task_struct
、mm_struct
、页表等相关的数据结构,并通过页表建立虚拟内存和物理内存之间的映射关系。如果与我们的文件管理联系起来,就是一个磁盘文件log.txt
加载进内存形成内存文件,最后加入对应双向链表中管理起来。
当文件存储在磁盘上时,我们称之为磁盘文件。而当磁盘文件被加载到内存中后,就变成了内存文件。磁盘文件与内存文件的关系,恰似程序和进程的关系。程序在运行起来后成为进程,同样,磁盘文件在加载到内存后成为内存文件。磁盘文件主要由两部分构成,即文件内容和文件属性。文件内容指的是文件中存储的数据,而文件属性则是文件的一些基本信息,包括文件名、文件大小以及文件创建时间等。这些文件属性也被称为元信息。在文件加载到内存的过程中,一般会先加载文件的属性信息。这是因为在很多情况下,我们可能只需要了解文件的基本属性,而不一定立即需要对文件内容进行操作。当确实需要对文件内容进行读取、输入或输出等操作时,才会延后式地加载文件数据。这样的设计可以提高系统的效率,避免在不必要的时候浪费资源加载大量的文件数据。
相关文章:

[Linux]:文件(上)
✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:Linux学习 贝蒂的主页:Betty’s blog 1. C语言文件操作 C语言文件操作接口如下,详情可参照——C语言文…...
flutter开发多端平台应用的探索 下 (跨模块、跨语言通信之平台通道)
前文 Flutter 是一个跨平台的开发框架,它允许开发者使用相同的代码库来构建 iOS、Android、Web 和桌面应用程序。 上文flutter开发多端平台应用的探索 上(基本操作)-CSDN博客列举了一些特定平台的case(桌面端菜单,鼠…...

第15-02章:理解Class类并获取Class实例
我的后端学习大纲 我的Java学习大纲 1、Java反射机制原理图: 源代码通过Javac编译得到字节码文件,当我执行到new一个对象的时候,字节码文件会通过ClassLoader被加载,然后得到一个Class类对象,存放在堆中,加…...

【Authing身份云-注册安全分析报告-无验证方式导致安全隐患】
前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 1. 暴力破解密码,造成用户信息泄露 2. 短信盗刷的安全问题,影响业务及导致用户投诉 3. 带来经济损失,尤其是后付费客户,风险巨大,造…...

idea插件推荐之Cool Request
Cool Request是一款基于IDEA的HTTP调试工具,可以看成是轻量版的postman,它会自动扫描项目代码中所有API路径,按项目分组管理。一个类被定义为Controller且其中的方法被RequestMapping或者XXXMapping注解标注以后就会被扫描到。 对应方法左侧会…...

从卫星和飞机等不同传感器方面由QGIS 遥感分析
在地理信息科学 (GIS) 中,遥感是指从远处获取有关地球表面特征信息的行为。遥感数据是从许多不同的平台获取而来,包括卫星、飞机和具有许多不同传感器的固定仪器,包括光谱图像(相机)和激光雷达。最常见的遥感数据形式是卫星和航空图像。 为了充分实现这些照片的价值,需要…...
什么是AIGC?有哪些免费工具?
AIGC(AI Generated Content),即“人工智能生成内容”,是指通过人工智能技术自动生成各种类型的数字内容。AIGC 让机器能够根据输入的信息或数据生成符合人类需求的文本、图像、音频、视频等内容,极大提高了内容创作的效…...

腾讯云升级多个云存储解决方案 以智能化存储助力企业增长
9月6日,在腾讯数字生态大会腾讯云储存专场上,腾讯云升级多个存储解决方案:Data Platform 数据平台解决方案重磅发布,数据加速器 GooseFS、数据处理平台数据万象、日志服务 CLS、高性能并行文件存储 CFS Turbo 等多产品全新升级&am…...
Kubernetes 集群初步部署
Kubernetes 集群初步部署 目标 本手册旨在指导您在多台虚拟机上部署一个基础的Kubernetes集群,并安装必要的工具和组件。 准备工作 确保所有虚拟机已经准备好,并且具有足够的资源来运行Kubernetes集群。虚拟机操作系统版本一致,推荐使用R…...

从源码到成品:直播美颜SDK与主播美颜工具的开发全流程
本篇文章,小编将带你深入了解从源码到成品的开发全流程,探讨如何构建一个功能完善的直播美颜SDK与主播美颜工具。 一、需求分析与技术规划 在开发任何工具之前,需求分析是第一步。在美颜工具的开发过程中,需要明确以下几点&…...

AMD EPYC 9004服务器内存配置深度分析:为何全通道填充是关键?
在一次技术沟通中,客户询问在部署AMD EPYC 9004服务器时,是否应该完全填充内存通道? 考虑到AMD正在用5年的更新周期替换其AMD EPYC 7002 “Rome”和Cascade Lake一代的服务器,他们认为通过减少内存插槽的填充,可以节省…...
redis的事务与管道有什么不同?
Redis 的事务(MULTI/EXEC)和管道(PIPELINE)都是为了执行多条命令,但它们的工作原理和目标不同。以下是两者的详细对比。 1. Redis 事务 (MULTI/EXEC) 特点: 事务的本质:Redis 事务是一组命令的…...
Redis 配置
一、关系型数据库与非关系型数据库 1. 关系型数据库 关系型数据库是一种结构化数据库,基于关系模型(二维表格模型),适合记录数据。通过 SQL(结构化查询语言)进行数据的检索和操作。主流的关系型数据库包括…...

【Qt笔记】QTableWidget控件详解
目录 引言 一、QTableWidget的特点 二、QTableWidget基础 2.1 引入QTableWidget 2.2 基本属性 三、代码示例:初始化QTableWidget 四、编辑功能 4.1 设置单元格为只读 4.2 响应内容更改 五、选择模式 六、样式定制 七、与其他控件的交互 7.1 在单元格…...

高低压配电系统中电弧光的危害有多大?
摘要 故障电弧是一种常见的电气故障现象,尤其在配电系统中,可能对设备安全和电力供应造成严重影响。本文旨在探讨故障电弧对配电系统的危害,并提出相应的预防措施,以增强系统的可靠性和安全性。通过对故障电弧的形成机制、危害分…...

安宝特案例 | AR如何大幅提升IC封装厂检测效率?
前言:如何提升IC封装厂检测效率? 在现代电子产品的制造过程中,IC封装作为核心环节,涉及到复杂处理流程和严格质量检测。这是一家专注于IC封装的厂商,负责将来自IC制造商的晶圆进行保护、散热和导通处理。整个制程繁琐…...

QGIS 如何连接空间库,并实时编辑空间表?编辑后库表如何刷新,保证是最新数据?
文章目录 一、什么是 qgis?二、qgis 如何连接数据库三、实时编辑空间表四、编辑后库表如何刷新,保证是最新数据?五、总结 一、什么是 qgis? QGIS(原称Quantum GIS)是一个用户界面友好的开源桌面端软件&…...

CleanClip for mac(苹果电脑剪切板管理器)
CleanClip 是一款为 Mac 设计的强大剪贴板管理工具,它能够显著提升你的工作效率和生产力。无论是在日常办公中还是进行创意设计,CleanClip 都能帮助你更轻松地管理和使用剪贴板内容。让我们一起来探索一下这个功能丰富的软件吧! 下载地址&am…...

嵌入式栈溢出怎么办?
在写文件的时候,因为把FATFS这些数据结构定义在了函数里,所以栈溢出了,我把比较大的数据结构放在全局变量上,就没事了.目前仅测试阶段,也可以放在堆里.不用的时候释放掉,减少耦合度.或者加static....

工厂安灯系统在优化生产流程上的优势
工厂安灯系统通过可视化的方式,帮助工厂管理者和操作工人及时了解生产状态,快速响应问题,从而优化生产流程。 一、安灯系统实时监控与反馈 安灯系统的核心功能是实时监控生产线的状态。通过在生产现场设置灯光、显示屏等设备,工人…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...

基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...