Linux学习之路 -- 文件 -- 文件操作

在学习C语言时,我们就学习过文件相关的内容,但是由于知识储备尚且不足,无法深入的了解文件,下面我们就要重新认识一下文件。

<1> 简单介绍(铺垫)

1.前面我们说过,文件 = 内容 + 属性,所以我们对文件的操作也就分为对属性和内容的操作。

2.通常我们在访问文件之前,都得先打开文件,打开文件这个操作就必须通过执行代码的方式来完成修改。 而修改这个动作是由cpu来执行的,cpu只能通过访问内存的方式来执行代码修改文件, 所以文件必需被加载到内存中,方便cpu对其进行修改。

3. 是谁打开的文件呢?我们执行修改文件代码前,这段代码会先变成进程,然后再由cpu调度进程打开文件。所以实际上打开文件的是进程。

4.一个进程可以打开多少文件?进程是可以打开多个文件

总结一下上面四点,在一定的时间段内,系统中存在多个进程,同时可能存在更多的被打开的文件,操作系统肯定是要管理这些文件,根据先描述,再组织的原则,内核中一定会有描述被打开文件的数据结构(这里假定是struct),并且用其定义对象。后面要研究的问题就变成了PCB和struct XXX的关系。当然,上述的文件都是被打开的文件,也叫内存文件。至于没有打开文件,一般就在磁盘上。

<2>重温一下C语言的文件接口 -对比一下重定向

下面主要重新介绍一下文件的打开,关闭和读写函数。由于文件操作函数在C语言阶段已经有所涉猎,所以这里重点介绍与重定向的关系。

在介绍它们的关系之前,我们先回顾一下文件函数的相关参数。

pathname表示路径名称,但实际上我们只要输入文件名即可,默认是在当前路径下查找(原因后面介绍)。mode主要是打开文件的模式,这里主要介绍一下w,r,a。其他的模式大同小异,大家可自行查阅复习。

其中W就是表示以写方式打开文件,如果文件不存在,就自动创建该文件。

#include<stdio.h>
#include<unistd.h>
#include<string.h>#define filename "file.txt"
int main()
{FILE* p = fopen(filename,"w");if(p == NULL){perror("fopen");}fclose(p);
}

运行结果:

下面我们再用文件读写函数对文件进行写入,这里为了方便显示,我们使用fputs函数

这个函数的参数就是把s这个字符串打印到stream这个文件流里面,这个文件流就是其实就可以看成是文件。

演示代码

#include<stdio.h>
#include<unistd.h>
#include<string.h>#define filename "file.txt"
int main()
{FILE* p = fopen(filename,"w");if(p == NULL){perror("fopen");}const char* str = "hello world\n";fputs(str,p);fclose(p);
}

上面这段代码其实很简单,我们把写入文件的操作去掉,再次运行代码,就会发现文件内容被清空,这是因为文件以W方式打开,会以覆盖的方式写入(就是在打开文件时会清空文件)。下面我们如果我们用echo命令重定向一下,我们再看一下文件的内容。

我们可以发现,重定向的操作其实和文件以读方式打开文件效果上是一样的,所以我们可以推出输出重定向时就是文件以(w)读的方式打开。

同理可得,我们可以推出,当我们使用追加重定向和输出重定向时,就是以a(append) 和 r(read)的方式打开文件。

文件操作在默认在当前路径的原因

我们在执行文件操作时,一定是由进程来实施操作。而我们之前说过/proc目录下,存在关于进程的大量信息,其中里面包含了进程当前的所处路径cwd。

下面复用上文的代码演示一下

#include<stdio.h>
#include<unistd.h>
#include<string.h>#define filename "file.txt"
int main()
{FILE* p = fopen(filename,"w");if(p == NULL){perror("fopen");}const char* str = "hello world\n";printf("pid: %d\n",getpid());while(1){fputs(str,p);sleep(2);}fclose(p);return 0;
}

进程的信息和相关结果

如果我们需要修改文件路径,我们就可以使用chdir函数,修改进程的工作路径,此时我们再运行程序,文件就会在修改后的路径里面被创建。

程序默认打开的文件流

一般来说,我们写的程序都是向显示器这个文件打印,但是我们自己却从来没有打开过显示器文件,而我们默认就能使用该文件进行打印,说明系统在打印之前就帮我们打开了文件。其中这里的文件包含了好几个

stdin输入流文件,叫做标准输入,默认是键盘设备;stdout输出流文件,叫做标准输出,默认是显示器设备;stderr 叫做标准错误,默认是显示设备。stdout可以从stdin里面读取信息,然后将其打印到显示屏上。而这些文件流是可以直接使用。

下面用一些接口来演示一下stdout这个输出流

#include<stdio.h>
#include<unistd.h>
#include<string.h>#define filename "file.txt"
int main()
{printf("hello world\n");fprintf(stdout,"hello world\n");fputs("hello\n",stdout);
}

运行结果

stdin输入流和stdout输出流类似,只不过一个是做输入一个做输出,我们读取数据时可以从stdin里面进行读取,而读取操作就可以使用scanf,fscanf等函数,下面就不具体演示了。而stderr先简单了解即可,后面再叙述。

<3>文件操作的系统调用接口

我们所使用的文件大多在磁盘进行存储,而磁盘属于底层的硬件,我们作为用户是无法直接修改底层硬件的数据,只有操作系统才有权力修改。虽然我们能够使用一些C语言的文件操作接口对文件进行修改,但这些接口最后都是封装的系统调用,下面我们就来聊一聊文件操作相关的系统调用。

<1>open

该接口用于打开文件,返回值为一个整数,如果打开成功,就会返回一个整数,这个整数叫做文件描述符,而文件如果打开失败,就返回-1。

这里的pathname字符串记录着要打开文件的名称,flags这个整数表示打开文件的方式, 我们一般用宏来表示这些方式。这些宏一般是用位图的方式来区分的,简单点说就是在32个比特位上的0变为1,不同的宏变化的比特位是错位的。这样我们就能使用按位或的操作实现用一个整数表示多个文件打开方式(按位或:两个比特位均为零才是零,其余皆是1)。

下面的宏代表了文件打开的各种模式

  1. O_RDONLY: 以只读方式打开文件。
  2. O_WRONLY: 以只写方式打开文件。
  3. O_RDWR: 以读写方式打开文件。
  4. O_APPEND: 追加数据到文件末尾。
  5. O_CREAT: 如果文件不存在,则创建它。
  6. O_EXCL: 与 O_CREAT 一起使用,如果文件已存在,则返回错误。
  7. O_TRUNC: 如果文件已存在,则截断它到零长度。(清空文件内容 )
  8. O_NONBLOCK: 非阻塞模式打开文件。
  9. O_SYNC: 同步写入,数据立即写入磁盘。
  10. O_DSYNC: 同步写入,数据写入磁盘后再返回。
  11. O_RSYNC: 同步读取,读取操作等待数据写入磁盘完成后进行。
  12. O_NOCTTY: 防止文件成为控制终端。
  13. O_CLOEXEC: 在执行 exec 函数族后自动关闭文件描述符。

如果我们要实现fopen中的w功能,我们就可以给flag参数传 O_RDONLY | O_CREAT。

如果我们使用第二个open系统调用接口,mode就表示文件的权限,这个带mode参数的系统open接口是在文件不存在时调用,mode参数就表示在创建文件时的文件权限。如果是正常的普通文件,我们输入0666即可。需要注意的是,文件的权限还受权限掩码的约束,所以我们输入的文件权限并不是最终的文件权限。当然,如果不想受权限掩码的约束,我们直接调用umask的系统调用接口,并且直接将权限掩码设置为零即可

<2>close

当我们对文件的操作结束时,我们就需要关闭文件,此时我们就可以使用close接口来关闭文件。这个接口的使用非常简单只需要将open接口的返回值传入close即可。

<3>write

write接口就是向文件里面写入内容,其操作和fwrite差不多。

fd就是文件描述符,buf就是要写入文件的内容的头指针,count表示写入文件字节总数。

下面演示一下,用w方式打开文件,并写入一些内容

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/types.h>#define filename "file.txt"
int main()
{int fd = open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);if(fd == -1){perror("open fail");return 1;}const char* str = "hello world\n";write(fd,str,strlen(str));close(fd);return 0;
}

结果

如果我们要追加,就可以把O_TRUNC修改成O_APPEND即可,通过灵活运用各种宏的组合,我们就可以实现C语言中文件操作的各种特性。

以上就是所有内容,文中如有不当之处,还望各位大佬指正,谢谢!!!

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

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

相关文章

4.2_文本处理工具

## 1.grep ## grep [Globally search a Regular Expression and Print] &#xff08;1&#xff09;grep 格式 ##grep 格式## grep 匹配条件 处理文件 grep root passwd #过滤root关键字 grep -E egrep #扩展搜索 grep -i root passwd ##忽…

深度学习之基于Vgg16卷积神经网络印度交警手势识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 随着智能交通系统的发展&#xff0c;手势识别技术成为了一个关键组成部分&#xff0c;特别是在交通管…

基于SSM SpringBoot vue宾馆网上预订综合业务服务系统

基于SSM SpringBoot vue宾馆网上预订综合业务服务系统 系统功能 首页 图片轮播 宾馆信息 饮食美食 休闲娱乐 新闻资讯 论坛 留言板 登录注册 个人中心 后台管理 登录注册 个人中心 用户管理 客房登记管理 客房调整管理 休闲娱乐管理 类型信息管理 论坛管理 系统管理 新闻资讯…

ArrayList还是LinkedList?

引言 集合作为一种存储数据的容器&#xff0c;是我们日常开发中使用最频繁的对象类型之一。JDK为开发者提供了一系列的集合类型&#xff0c;这些集合类型使用不同的数据结构来实现。因此&#xff0c;不同的集合类型&#xff0c;使用场景也不同。 很多同学在面试的时候&#x…

多列列表OCX控件

VB6写的一个多列列表OCX控件源码&#xff0c;核心就是利用数组划分成多列数据&#xff0c;可装载亿条数据以上&#xff0c;控件引用了四个PictureBox控件分别作为:索引号显示&#xff0c;列表&#xff0c;垂直滚动条和横向滚动条&#xff0c;基本实现列表的添加、修改和删除等功…

文本嵌入的隐私风险:从嵌入向量重建原始文本的探索

随着大型语言模型&#xff08;LLMs&#xff09;的广泛应用&#xff0c;文本嵌入技术在语义相似性编码、搜索、聚类和分类等方面发挥着重要作用。然而&#xff0c;文本嵌入所蕴含的隐私风险尚未得到充分探讨。研究提出了一种控制生成的方法&#xff0c;通过迭代修正和重新嵌入文…

TCP 协议

TCP协议段格式 源/目的端口号&#xff1a;表示数据是从哪个进程来&#xff0c;到哪个进程去。 序号&#xff1a;发送数据的序号。 确认序号&#xff1a;应答报文的序号&#xff0c;用来回复发送方的。 4 位首部长度&#xff1a;一个 TCP 报头&#xff0c;长度是可变的&#xff…

简化Transformer模型,以更少的参数实现更快的训练速度

在深度学习领域&#xff0c;Transformer模型因其卓越的性能而广受欢迎&#xff0c;但其复杂的架构也带来了训练时间长和参数数量多的挑战。ETH Zurich的研究人员Bobby He和Thomas Hofmann在最新研究中提出了一种简化的Transformer模型&#xff0c;通过移除一些非必要的组件&…

【VueUse】超越基本功能的高级 Vue 元素操作

在vue开发中我们经常需要操作DOM元素&#xff0c;从简单的添加类到动态创建元素&#xff0c;这些操作都是不可避免的。而在VueUse库中&#xff0c;Elements相关API函数为我们提供了一系列强大而灵活的工具&#xff0c;帮助我们更轻松地处理DOM元素。无论是优雅地处理元素、动态…

JavaEE技术之MySql高级(索引、索引优化、sql实战、View视图、Mysql日志和锁、多版本并发控制)

文章目录 1. MySQL简介2. MySQL安装2.1 MySQL8新特性2.2 安装MySQL2.2.1 在docker中创建并启动MySQL容器&#xff1a;2.2.2 修改mysql密码2.2.3 重启mysql容器2.2.4 常见问题解决 2.3 字符集问题2.4 远程访问MySQL(用户与权限管理)2.4.0 远程连接问题1、防火墙2、账号不支持远程…

从永远到永远-和弦-挂留和弦

挂留和弦 1.概念2.指型1.Xsus2和弦2.Xsus4和弦 3.应用 1.概念 该篇说下和弦中的“渣男”、“绿茶”&#xff0c;挂留和弦。 挂留&#xff08;suspended&#xff09;和弦是将三和弦的三音替换成大二度或纯四度音形成的&#xff0c;包括挂留二和弦、挂留四和弦两种。 三音是一个…

手撕vector的模拟实现

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary_walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

JDK14特性

JDK14 1 概述2 语法层面的变化1_instanceof的模式匹配(预览)2_switch表达式(标准)3_文本块改进(第二次预览)4_Records 记录类型(预览 JEP359) 3 API层面的变化4 关于GC1_G1的NUMA内存分配优化2_弃用SerialCMS,ParNewSerial Old3_删除CMS4_ZGC on macOS and Windows 4 其他变化1…

自学Redis7入门篇一

自学Redis7入门篇一 Redis概述一、Redis是什么&#xff1f;二、Redis能干什么&#xff1f;三、去哪里下四、Redis安装配置五、Redis 10数据类型1.字符串(String)2.列表(List)3.哈希表(Hash)4.集合(Set)5.有序集合(ZSet)6.地理空间(GEO)7.基数统计(HyperLogLog)8.位图(bitmap)9.…

计算机毕业设计PHP+vue体检预约管理系统d1yu38

防止在使用不同数据库时&#xff0c;由于底层数据库技术不同造成接口程序紊乱的问题。通过本次系统设计可以提高自己的编程能力&#xff0c;强化对所学知识的理解和运用 本系统是一个服务于医院先关内容的网站&#xff0c;在用户打开网站的第一眼就要明白网站开发的目的&#x…

01.本地工作目录、暂存区、本地仓库三者的工作关系

1.持续集成 1.持续集成CI 让产品可以快速迭代&#xff0c;同时还能保持高质量。 简化工作 2.持续交付 交付 3.持续部署 部署 4.持续集成实现的思路 gitjenkins 5.版本控制系统 1.版本控制系统概述2.Git基本概述3.Git基本命令 2.本地工作目录、暂存区、本地仓库三者的工作关系…

[数据结构]———归并排序

具体代码&#xff1a;在gitee仓库&#xff1a;登录 - Gitee.com 目录 ​编辑 1.基本思想&#xff1a; 2. 代码解析 1.分析 2.逻辑图 3.运行结果 1.基本思想&#xff1a; 归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法,该算法是采用分…

算法打卡day40

今日任务&#xff1a; 1&#xff09;139.单词拆分 2&#xff09;多重背包理论基础&#xff08;卡码网56携带矿石资源&#xff09; 3&#xff09;背包问题总结 4&#xff09;复习day15 139单词拆分 题目链接&#xff1a;139. 单词拆分 - 力扣&#xff08;LeetCode&#xff09; …

Pytorch学习笔记——TensorBoard的初使用

1、TensorBoard介绍 TensorBoard是TensorFlow的可视化工具&#xff0c;但它也可以与PyTorch结合使用。TensorBoard提供了一个Web界面&#xff0c;可以展示你训练过程中的各种信息&#xff0c;如损失值、准确度、权重分布等&#xff0c;更好地帮助开发者理解和调试模型。 Tenso…

huggingface里如何查看具体任务的评估指标

如果我们在做一个模型训练任务的时候&#xff0c;可能会不知道这个任务在评估的时候使用什么指标&#xff0c;那么huggingface里边为我们提供了参考&#xff1a; 下面就来看看吧&#xff1a; https://huggingface.co/https://huggingface.co/ 点击"Docs"&#xff…