【Linux】基础IO_文件操作

  环境:centos7.6,腾讯云服务器
Linux文章都放在了专栏:【Linux】欢迎支持订阅

相关文章推荐:

【Linux】冯.诺依曼体系结构与操作系统

【C/进阶】如何对文件进行读写(含二进制)操作?


预备知识

在C语言阶段,我们学习过相关文件操作,但是,我们真的了解文件操作吗?

  • 答案是并不了解,因为我们之前所学习的C语言文件操作,都是属于语言层面的操作,我们只是知道了fopen,fclose这些函数是怎么用,但是具体的底层原理并没有涉及接触。实际上,当涉及到文件操作的原理时,就不再是简单的语言问题,而是属于系统问题

是否只有我们的C/C++才可以对文件进行操作呢?

  • 答案也是否定的,其它比如JAVA、Python等语言也支持相关文件操作,只是不同语言的实现方法(语言级别)不同罢了,但是底层(系统级别)都会涉及到系统层面的相关操作

如何看待文件?

  • 文件=内容属性对文件的相关操作--->对内容/属性的相关操作
  • 文件存放在磁盘中,只有当我们打开文件进行相关操作时,文件的属性会被加载到内存冯诺伊曼体系结构决定,CPU只与内存交互)
  • 对于大量被打开的文件,OS会进行管理,OS会创建struct file结构体,该结构体内包含对应文件的属性(先描述),然后通过某种数据结构,将各个文件对应的结构体连接起来(再组织)。对被打开文件的管理--->对该数据结构的增删查改。

文件是怎么打开的?由谁打开?

  • 用户通过创建进程(写代码,编译运行),底层会通过系统调用,从而让OS打开文件
  • 本章所讨论的文件操作都是针对被打开的文件

文件操作

语言级别的文件操作(C)

文件的打开

 FILE *fopen(const char *path, const char *mode);

对于该函数path表示打开或创建的目标文件(默认会在当前路径下创建/打开),mode表示文件的打开方式。对于mode来说,这里就简单介绍以下几种(更多的在前文:点击跳转):

打开方式含义假如文件不存在
"w"(只写)为了输出数据,打开一个文本文件自动创建该文件,并且在写入前会清空原文件
"r"(只读)

为了输入数据,打开一个已经存在的文件

打开失败
"a"(追加)向文本文件尾添加数据自动创建该文件,追加前不会清空原文件
FILE* fp1=fopen("./TEST/log.txt", "w");//只写,文件不存在在,在./TEST/下创建该文件
FILE* fp2=fopen("log.txt","a");//追加,文件不存在,在当前路径下创建该文件
FILE* fp3=fopen("log.txt","r");//只读,同一个文件可以被打开多次

文件的关闭

int fclose(FILE *fp);//对已打开的文件进行关闭。

对于一个被打开的文件,最后一定要关闭该文件。这就好比我们malloc出来的空间一定要free一样。fclose与fopen配套使用。

fclose(fp1);  
fclose(fp2);  
fclose(fp3);

文件的写入

C语言提供的写函数一共有以下几种:

函数功能适用于
fputc以一个字符为单位进行写入所有输出流
fputs以一行为单位进行写入所有输出流
fwrite二进制写入文件
fprintf格式化写入所有输出流
snprintf格式化写入所有输出流

对于上面的大多数函数,这里就不做过多讲解,可以自行前去观看,这里讲一下snprintf。snprintf是fprintf的优化版本,相较于fprintf,可以对写入数据进行长度控制,会更加安全。

int snprintf(char *str, size_t size, const char *format, ...);
  • str:表示要写入的缓冲区的地址
  • size表示该缓冲区的大小
  • format:格式化可变参数(比如:"%d:%s\n",x,y )

演示代码如下:

 #include<stdio.h>
 #include<stdlib.h>
 
 #define SIZE 128
 
 int main()
 {
   FILE* fp=fopen("log.txt","w");//写
   //打开失败返回空
   if(fp==NULL)
   {
     perror("fopen fail\n");
     exit(-1);
   }
   char buffer[SIZE];
   int cnt=10;
   const char* st="hello world!";
   while(cnt)
   {
     //格式化写入到buffer数组
     snprintf(buffer,sizeof(buffer),"%d:%s\n",cnt,st);
     //再将数组内容写到文件                                                                                                                    
     fputs(buffer,fp);
     --cnt;
   }
   //关闭文件
   fclose(fp);
   return 0;
 }

文件的读取

对于文件的读取,C提供的函数与上面一一对应,用法也是如此

文件读取演示:

 #include<stdio.h>
 #include<stdlib.h>
 #include<string.h>
 #define SIZE 128
   
 //文件的读取
 
 int main()
 {
   FILE* fp=fopen("log.txt","r");//读方式打开
   if(fp == NULL)
   {
     perror("fopen fail\n");
     exit(-1);
   }
   //按行来读取文件
   while(1)
   {
     //从文件流中按行读取内容,读到tmp中
     char tmp[SIZE];
     if(fgets(tmp,sizeof(tmp),fp)==NULL)
     {
       break;
     }
     //打印tmp
     printf("%s",tmp);                                                                                                                         
   }
   //关闭文件
   fclose(fp);
   return 0;
 }

系统级别的文件操作

以上都是语言级别的文件相关操作。至此往下将讲解系统级别的相关文件操作。

文件的打开

对于文件的打开,我们采用open系统调用函数。如下:

//头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

//系统调用函数open
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

对于该函数,有如下理解:

  • 返回值:打开成功,返回一个int类型的整数->文件描述符(下一章将重点讲解),失败返回-1。
  • 参数pathname打开或创建的目标文件(默认在当前路径打开/创建)。
  • 参数flags多参数选项,用一个整形来实现多个选项的传递。以下为flags对应的参数选项,通常用或位运算来表示一个或多个参数。

对于多参数选项flags

参数选项含义
O_RDONLY只读
O_WRONLY只写
O_CREAT若文件不存在则创建该文件,与open的第三个参数mode(设置权限)配套使用
O_APPEND追加
O_TRUNC打开文件前清空原文件

多参数传递实际上采用的就是位图的方式来实现,一个整形一共32个比特位,每一个比特位都可以用来表示一个参数,用|运算符则可以实现一个整形传递多个参数选项

我们可以利用此特点来自己实现一个小demo,如下图所示:

参数flags便是利用此特点来实现一个整形多个参数选项。与我们的C语言对应关系如下;

  •  参数mode创建文件时给文件一个权限

文件的关闭

通过系统调用函数close来关闭一个文件,该函数如下:

#include <unistd.h>

int close(int fd);

其中这里的fd就是文件描述符,也就是open函数返回的那个整形。具体含义将在下一篇详细讲解。

文件写入

通过函数write来实现文件的写入操作

#include <unistd.h>

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

对于该函数:

  • 返回值:写入成功,会返回写入的内容的大小(单位:字节)失败返回-1
  • 参数fd:文件描述符即open函数的返回值
  • 参数buf:缓冲区的地址
  • 参数count:表示写入的文件的大小

具体案例操作:

 #include<stdio.h>
 #include<stdlib.h>
 #include<string.h>
 #include<unistd.h>
 #include<sys/types.h>
 #include<sys/stat.h>
 #include<fcntl.h>
 
 #define SIZE 128
 
 int main()
 {
   umask(0);//设置umask为0
   int fd=open("log.txt",O_CREAT|O_WRONLY|O_TRUNC,0666);//以写的方式打开文件,文件不存在则创建,打开之前会清空原文件,创建时文件权限为0666
   //打开失败
   if(fd == -1)
   {
     perror("open fail\n");
     exit(-1);
   }
 
   char buffer[SIZE];//充当缓冲区的buffer数组
   const char* str="hello world";
   int cnt=10;
   //利用snprintf进行格式化写入到缓冲区,再写入到文件
   while(cnt)                                                                                                                                  
   {
     snprintf(buffer,sizeof(buffer),"%d:%s\n",cnt,str);
     --cnt;
     ssize_t n=write(fd,buffer,strlen(buffer));//这里我们不需要将/0计算在内,因为/0是C语言规定的字符串结尾,此时我们处于系统级别
     printf("成功写入%lu个字节内容\n",n);//%lu:无符号整型

     //间隔1秒写入一次                                                                                                                        
    sleep(1);
   }
   //关闭文件
   close(fd);
   return 0;
 }

运行结果如下:

文件的读取

对于文件的读取,提供了函数read

#include <unistd.h>

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

 对于该函数:

  • 返回值:读取成功,返回读取的内容的大小,失败返回-1
  • 参数fd:文件描述符
  • 参数buf:缓冲区地址,用来存放读到的数据
  • count:一次读取字符的大小到缓冲区buf

具体操作如下:

 #include<stdio.h>
 #include<stdlib.h>
 #include<string.h>
 #include<unistd.h>
 #include<sys/types.h>
 #include<sys/stat.h>
 #include<fcntl.h>
 
 #define SIZE 128
 
 //文件读取
 
 int main()
 {
   int fd=open("log.txt",O_RDONLY);//读方式打开文件
   if(fd== -1)
   {
     perror("open fail\n");
     exit(-1);                                                                                                                                 
   }
   char buffer[SIZE];//读到的内容放进buffer数组
   //注意处理\0
   ssize_t n=read(fd,buffer,sizeof(buffer)-1);
   //读取成功
   if(n>0)
   {
     buffer[n]='\0';
     printf("%s共读取%lu字节的内容\n",buffer,n);//字符串结尾的标志\0(这里我们用printf打印,属于C语言级别,所以得考虑\0的存在)
   }
   //关闭文件
   close(fd);
   return 0;
 }

运行结果如下:

语言操作与系统级别的文件操作区别

实际上,我们所有的语言级别的文件操作都是对系统调用的封装,比如我们使用的fclose,fopen等函数,他们的底层实际上都会调用对应的系统级别的函数,比如close、open等。也就是说,语言级别的文件操作的底层,并不会直接跳过OS,而是一层一层往下进行。


end.

生活原本沉闷,但跑起来就会有风!🌹 

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

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

相关文章

Docker 部署Jira8.1.0

Jira与Confluence一样&#xff0c;都需要用到独立的数据库&#xff0c;对于数据库的安装我们不做介绍&#xff0c;主要介绍如何用Docker部署Jira以及对Jira进行破解的操作。 1、数据库准备 关于数据库官方文档说明&#xff1a;https://confluence.atlassian.com/adminjiraserv…

憨批的语义分割重制版11——Keras 搭建自己的HRNetV2语义分割平台

憨批的语义分割重制版11——Keras 搭建自己的HRNetV2语义分割平台学习前言什么是HRNetV2模型代码下载HRNetV2实现思路一、预测部分1、主干网络介绍a、Section-1b、Section-2c、Section-3d、Section-42、特征整合部分3、利用特征获得预测结果二、训练部分1、训练文件详解2、LOSS…

stm32 esp01s Qt 巴法云平台控制小灯

最近一直在想着用esp01s和stm32做个控制的东西&#xff0c;现在先把现在做好的一部分写出来&#xff0c;巴法云平台我觉得是一个不错物联网平台&#xff0c;接口文档资料都十分清晰。 这个demo是esp1s和stm32串口通信&#xff0c;然后qt上位机和esp01s是tcp通信 这样就可以实现…

C++模板基础(六)

类模板与成员函数模板 ● 使用 template 关键字引入模板&#xff1a; template class B {…}; – 类模板的声明与定义 翻译单元的一处定义原则 template<typename T> class B; //类模板的声明template<typename T> class B //类模板的定义 {};template<typenam…

故障定级和定责

故障管理的第一步是对故障的理解&#xff0c;只有正确地面对故障&#xff0c;我们才能够找到更合理的处理方式。 这便需要做两个工作&#xff1a;一是跟踪线上故障处理和组织故障复盘&#xff0c;二是制定故障定级定责标准&#xff0c;同时有权对故障做出定级和定责。 所以&a…

处理机调度与死锁习题

1.对于下列三个作业&#xff0c;采用不可抢占的调度方式&#xff1a;先来先服务&#xff08;&#xff26;&#xff29;&#xff26;&#xff2f;&#xff09;和短作业优先&#xff08;&#xff33;&#xff2a;&#xff26;&#xff09;调度算法&#xff0c;分别计算它们的平均…

蓝桥杯第十四届省赛完整题解 C/C++ B组

没有测评&#xff0c;不知道对不对&#xff0c;仅仅过样例而已 试题 A: 日期统计 本题总分&#xff1a;5 分 【问题描述】 小蓝现在有一个长度为 100 的数组&#xff0c;数组中的每个元素的值都在 0 到 9 的 范围之内。数组中的元素从左至右如下所示&#xff1a; 5 6 8 6 9…

Window常用命令

一、快捷键 1、自带快捷键 序号快捷键作用1windowsGXBOX录屏2cmd >osk屏幕键盘3cmd >calc计算器4cmd >mrt恶意软件删除工具 2、浏览器快捷键 序号快捷键作用1Alt P浏览器图片下载&#xff08;来自油猴脚本&#xff09; 二、其他功能 1、解决端口占用 第一步&…

Dubbo架构整体设计

一、Dubbo调用关系说明 1.1 组成部分 在这里主要由四部分组成: ● Provider: 暴露服务的服务提供方 Protocol&#xff1a;负责提供者和消费者之间的协议交互数据 Service&#xff1a;真实的业务服务信息&#xff0c;可以理解成接口和实现 Container&#xff1a;Dubbo的运行环境…

小规模容器编排使用Docker Swarm不香么,用个锤子的kubernetes

文章目录一、Docker Swarm是什么&#xff1f;二、Swarmkit和Swarm Mode是什么&#xff1f;三、Docker Swarm的核心设计四、Docker Swarm安装部署4.1、初始化Swarm节点14.2、新节点加入Swarm集群4.3、使用swarm部署服务4.4、swarm集群管理一、Docker Swarm是什么&#xff1f; D…

用于平抑可再生能源功率波动的储能电站建模及评价(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

手动挡科目三道路驾驶技能考试及理论考试要点

路线每个驾校的科目三路线可能都不一样&#xff0c;但是考点基本差不多。我当时选的驾校是北京公交驾校&#xff0c;路线图如下&#xff1a;考试要点在考试大厅等待叫号&#xff0c;一般大屏都会公布xxx学员找xx号车考试&#xff0c;这边白色车是手动挡&#xff0c;灰色车是自动…

智慧停车怎么实现的,停车场寻车是怎么实现的

智慧停车怎么实现的&#xff1f;随着汽车快速发展&#xff0c;停车场行业也面临着积极发展&#xff0c;由于停车场面积大&#xff0c;找到自己想去的停车位就成了一个大问题。而停车场地图可以根据地点、距离等给出最佳的路线规划&#xff0c;引导司机快速的到达目标停车位。 …

网络编程初探

1、概念 计算机和计算机之间通过网络进行数据传输 常见的软件构架&#xff1a;CS架构和BS架构 通信软件构架的优缺点 CS&#xff1a;客户端服务端模式需要开发客户端 BS&#xff1a;浏览器服务端模式不需要开发客户端 CS: 适合定制化的办公类软件如&#xff1a;IDEA&…

css 使用blur,实现背景色高斯模糊,但不影响背景上的内容

实现效果 实现原理 1.filter&#xff1a;blur() 2.伪元素设置&#xff0c;不影响子元素显示 <!-- 库位使用率 --><div class"bkPart statusPart"><div class"co-title">库位使用率</div><div class"pickPos"><…

游戏开发之Unity2021熟悉基本工具

接上一节通用渲染管线项目搭建 导入天空盒素材&#xff1a;在窗口中选择资源商店后会弹出下面的图片&#xff0c;在资源商店中找到我们想要的天空盒素材&#xff0c;将素材在unity中打开&#xff0c;如下面的第二幅图中就是我选择的天空盒素材&#xff0c;在这里可能会遇到一个…

Pandas 2.0正式版发布: Pandas 1.5,Polars,Pandas 2.0 速度对比测试

Pandas 2.0正式版在4月3日已经发布了&#xff0c;以后我们pip install默认安装的就是2.0版了&#xff0c;Polars 是最近比较火的一个DataFrame 库&#xff0c;最近在kaggle上经常使用&#xff0c;所以这里我们将对比下 Pandas 1.5&#xff0c;Polars&#xff0c;Pandas 2.0 。看…

redis杂谈之部分重同步的实现

背景&#xff1a; 部分重同步则用于处理断线后重复制情况&#xff1a;当从服务器在断线 后重新连接主服务器时&#xff0c;如果条件允许&#xff0c;主服务器可以将主从服务器连 接断开期间执行的写命令发送给从服务器&#xff0c;从服务器只要接收并执行这 些写命令&#xff…

[ 云计算 | Azure ] Chapter 05 | 核心体系结构之管理组、订阅、资源和资源组以及层次关系

本文主要对如下内容进行讲解&#xff1a;Azure云计算的核心体系结构组件中的&#xff1a;资源、订阅和资源组&#xff0c;以及了解 Azure 资源管理器 (ARM) 如何部署资源。 本系列已经更新文章列表&#xff1a; [ 云计算 | Azure ] Chapter 03 | 描述云计算运营中的 CapEx 与…

数据结构-插入排序

一.概要 插入排序是一种基于比较的排序算法&#xff0c;其基本思想是将待排序的元素插入到已排序的序列中&#xff0c;形成新的有序序列。 插入排序算法的过程如下&#xff1a; 将待排序序列分为两部分&#xff1a;已排序部分和未排序部分&#xff1b; 初始时&#xff0c;已…
最新文章