Linux之重谈文件和c语言文件接口

重谈文件

文件 = 内容 + 属性, 所有对文件的操作都是: a.对内容操作 b.对属性操作

关于文件 

一:
即使文件的内容为空,该文件也会在磁盘上也会占空间,因为文件不仅仅只有内容还有文件对应的属性,文件的内容会占用空间, 文件的属性也会占用空间,比如:

创建了一个文件没有往文件里面写入任何内容, 但文件的大小为0代表文件内容为空, 不代表文件本身不占用空间, 因为文件 = 内容 + 属性, 内容是数据, 属性也是数据 ---存储文件必须既存储内容又存储属性----默认就是磁盘上的文件.

对文件的操作等于对文件的属性进行操作或者对文件的属性和内容进行操作, 因为改变文件的属性不一定会改变文件的内容, 但是改变文件的内容一定会改变文件的属性, 比如:

修改之前的test.c文件: 

对test.c文件的内容进行修改, 多输入一行printf语句: 

对文件的内容做修改, 文件的内容和属性都发生变化. 

只对文件的属性进行操作, 比如说改变文件的拥有者, 所属组, 文件的权限和时间等等都是对文件的属性进行的操作:

进行文件操作时需要使用路径加文件名的方式以确保唯一性, 因为在不同的路径下可能会存在同名文件, 比如在上级目录下创建一个空文件test.c, 然后在其他路径下使用另外一个可执行程序来向test.c文件写入内容:

路径加文件名可以帮我们指明确定的文件.

四:
如果没有指名对应的文件路径, 默认是在当前路径进行访问, 这里的当前路径就是进程当前的路径,就是在哪个路径下执行的文件, 那么这个路径就是进程的当前路径。

 test.c:

 之前说过在根目录下proc文件夹里面存放许多文件夹, 这些文件夹以系统中的各种进程名为名, 并装着对应进程的各种信息:

此时就会显示两个链接文件, 链接文件exe表示的是该进程对应的文件在磁盘中的位置,链接文件cwd表示的是该进程的当前路径:

如果我们在其它路径下执行的这个程序,, 那么该程序的cwd就会变化,比如在家目录:

五:

当我们把fopen, fclose, fwrite等接口写完之后, 代码编译之后, 形成二进制可执行程序之后如果程序被没有执行, 则对应的文件操作是不会被执行的, 所以对文件的操作本质上就是进程对文件的操作.
我们访问一个文件时, 都是要先把这个文件先打开的, 这里的"我们" 其实是进程, 是进程要访问这个文件. 而文件打开前是一个普通的磁盘文件, 而CPU只与内存打交道, 所以文件打开后其实把文件加载到了内存, 加载磁盘上的文件, 一定涉及到访问硬件磁盘设备, 所以文件打开操作是由操作系统来做的.

六:

磁盘上有很多的文件, 但是并不是所有的文件都被打开了, 文件按照是否被打开, 分为: 被打开的文件(内存中) 和 未被打开的文件(磁盘中). 所以研究文件操作的本质就是进程与被打开文件的关系.

一个进程是可以打开多个文件的, 也就是说加载到内存中的文件可能存在多个, 操作系统要不要管理这些打开的文件呢? 如何管理? 先描述,再组织, 一个文件要被打开, 一定要在内核中形成被打开的文件对象, 所以对文件的管理转化为对链表的增删查改.

struct XXX
{
    //文件属性
    struct XXX* next;
};

 C语言文件调用函数

在谈系统调用接口之前先来谈谈c语言里面的文件调用函数.

fopen

操作文件之前首先需要打开文件, 在c语言里面打开文件使用fopen函数:

第一个参数表示要打开文件的文件名,  如果文件名没有带路径的话, 该函数就会在当前路径下查找并打开这个文件, 如果带了路径就会到指定路径下查找并打开这个文件.

第二个参数表示的是打开文件的方式, r表示只读也就是只能从文件中读取数据, w表示只写也就是只能往文件中写入数据, a表示的是往文件的后面尾插数据, 以w的形式打开文件如果文件名不存在的话会在当前路径下创建文件, 并且w方式打开文件会清空文件中原来的数据, 比如说下面的操作:

而之前在指令中使用过的输出重定向 > 追加重定向 >>, 实际上是分别以w方式和a方式打开文件: 

文件以w方式打开, 会先清空文件内容, 而使用 echo "hello world" > log.txt 是以输出重定向的方式向log.txt中写入hello world, 每次打开文件都会先清空, 所以如果直接 > log.txt , 可以直接清空该文件, 虽然什么内容都没有向文件内输入, 但是重定向会以"w"的方式打开文件, 打开文件就会清空文件.

文件以a方式打开, 是从文件结尾处开始写入, 是追加. 使用echo "hello world" >> log.txt, 以追加重定向的方式向log.txt中写入hello world, 每次写入之前的内容都不会被清除, 所以 >> 追加重定向是以"a"的方式打开文件.


fclose

既然有函数能够打开文件那么就会有函数关闭文件, 那这里的函数就是fclose函数, 该函数的介绍如下:

这个函数只有一个参数, 所以使用这个函数的时候直接将文件打开时创建的那个FILE*变量传给这个函数就可以关闭对应文件了 .


fwrite

size_t fwrite(const void* buffer,size_t size,size_t count,FILEstream);

从内存的变量中获取二进制数据,放到文件中
const void buffer表示获取数据的位置,size_t size一个变量类型的大小,size_t count表示读多少个这样类型的数据,FILE* stream为文件指针

fread

size_t fread( void buffer, size_t size, size_t count, FILE stream );

从文件中获取二进制数据, 放到内存的变量中

const void buffer表示获取数据的位置,size_t size一个变量类型的大小,size_t count表示读多少个这样类型的数据,FILE stream为文件指针


 


认识系统接口

c/c++都有文件操作接口, 每个语言都有文件操作接口, 并且每个语言操作接口都还不一样, 但是这些接口本质上都是调用操作系统提供的文件级别的系统调用接口来访问的文件, 而操作系统的接口只有一套, 不管库函数再怎么变化. 底层是不变的.

文件是在硬盘上的, 硬盘是外设, 外设是被操作系统管理的, 所有人想要访问磁盘都无法绕操作系统,所以访问文件一定要有系统调用接口, C语言打开文件的接口, 底层一定封装了系统调用接口.

标记位

宏喜欢用来作为标记位, 标记位的作用就是表明某件事情是否发生/存在, 如果发生了就传一个标记位, 在c语言中一般以一个整型变量作为标记位, 但是如果需要10个标记位的话那就得传10个变量用来表示10件事情已经发生这就有点麻烦, 所以结合之前学过的位图去判断是否存在的问题就十分合适了,用一个整形变量可以充当32个标记位.

首先标记位是一个宏, 这个宏实际上就是一个数字, 并且其对应的二进制位只有一位是1, 所以我们就可以采用这样的形式来创建标记位:

  1 #include <stdio.h>
  2 
  3 #define Print1 (1<<0) //0001
  4 #define Print2 (1<<1) //0010
  5 #define Print3 (1<<2) //0100
  6 #define Print4 (1<<3) //1000
  7 
  8 void Print(int flags)
  9 {
 10     if(flags & Print1) printf("hello 1\n");
 11     if(flags & Print2) printf("hello 2\n");
 12     if(flags & Print3) printf("hello 3\n");
 13     if(flags & Print4) printf("hello 4\n");                                                                                                                                                                   
 14 }
 15 
 16 int main()
 17 {
 18     Print(Print1); //hello 1
 19     Print(Print1 | Print2); //hello 1\n hello 2
 20     Print(Print1 | Print2 | Print4); //hello 1\n hello 2\n hello 4
 21     return 0;
 22 }

利用位图的原理, 想要执行哪条代码就输入对应的宏并用或运算符连接起来, 因为每一个宏都对应唯一的一个二进制1. 


open 

c语言里面是通过函数fopen来以各种不同的形式打开文件, 其实fopen是通过对系统调用接口open进行封装来实现的, open函数的介绍:

open函数有三个参数, 第一个参数pathname是文件路径, 第二个参数flags是打开方式也就是标志位, 第三个参数是权限, 如果文件已经存在, 只需要前两个参数. 文件不存在需要设置第三个参数, 否则创建出的文件没有权限.

部分标识符: 

选项宏

功能

O_RDONLY

只读打开

O_WRONLY

只写打开

O_RDWR

读,写打开

O_CREAT

若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限

O_TRUNC当源文件中存在内容时会将文件的内容进行清空

O_APPEND

追加写

注:O_RDONLY、O_WRONLY和O_RDWR只能三选一使用 .

其中第一个参数pathname可以添加路径也可以不添加路径, 不添加路径的话该函数就会在当前路径下查找文件. flags可以传很多的标志位, 先举两个例子, O_RDONLY表示只读标记符, O_WRONLY表示只写标记符, 和fopen里的 r 和 w 有点像.

我们可以通过下面的例子来证明一下两者的区别:

首先c语言中的w有两个特性:

1.如果源文件存在内容的话那么以只写方式打开文件的话, 会将源文件的内容清空。

2.如果打开的文件不存在的话, 那么fopen函数会自己创建一个文件.

我们来看看open函数的只写有没有上述的功能比如说下面的操作, 在当前路径下创建一个文件:

并没有自动创建文件

所以再介绍open函数的两个标记位: O_CREATO_TRUNC, 其中O_CREAT的作用就是当文件不存在时会自动创建一个文件, O_TRUNC的作用就是当源文件中存在内容时会将文件的内容进行清空(create是创建, trunc是截断), 所以使用c语言的fopen函数以w只读的形式打开文件时, 在底层就会调用open函数并以O_CREAT | O_TRUNC|O_WRONLY 作为标记位进行传参:

发现可以自动创建一个log.txt文件, 但是这个文件目前是红色的, 因为此时的文件里面都是乱码无法正常的使用, 造成这种现象的原因是因为在创建文件的时候没有给对应的权限, 也就是上面提到的遗漏了该函数的第三个参数, 当使用open函数创建文件时需要用第三个参数给创建的文件一个起始权限.

这里给了起始权限是0666, 但是这里创建出来的权限是0664, 因为这里创建的文件也遵循umask的原则, 所以创建出的文件的权限可能不是我们想要的.

这里要是想让创建的文件就是我们给的起始权限的话就可以使用umask函数, 可以在创建文件前先用umask(0), 先把权限掩码设置为0, 设置了权限掩码就会用设置的, 没设置umask就是系统默认的.但是程序中调用的umask函数不会影响命令行的umask值.

 

open函数返回值称为: 文件描述符fd.

使用open函数打开文件时open函数会返回一个整数, 这个整数就是文件描述符fd, 在其他函数里面就可以根据这个文件描述符来确定要写入的文件, 如果open返回的值为负数的话就表明此时文件打开失败.

我们可以看到此时打印的文件描述符为3,在后面的程序就可以使用这个文件描述符3来代表要被操作的文件mytest。


write

将一个文件以写的打开之后就可以往这个文件里面写入内容, 那么这里的写入就要用到write函数, 该函数的参数如下:

第一个参数fd是文件描述符表示要将内容写入哪个文件.

第二个参数表示写入文件的内容来自于哪个缓冲区, 这个指针会指向空间开始的位置, 并且指针的类型为void说明不管要写入的数据类型是什么这个函数都可以将数据写到文件里面, 就是因为在计算机看来所有的数据全部都是二进制, 我们平时说的二进制数据和文本数据只不过语言进行的封装罢了.

第三个参数表示写入文件的内容有多少个字节, 当这个函数执行完之后就会返回实际写入文件的字节个数.

比如说下面的代码: 

问题: write函数第三个参数需不需要传strlen(buf)+1 ?

outbuffer中有一段字符串abcde\n, 这个字符串的长度为6大小为6个字节而我们却想往文本里面写入7个字节的内容, 所以当函数写入的时候就会自动的在字符串后面添加上一个\0来补齐这7个字节的大小, 我们之所以这么认为是因为在c语言当中字符串是以\0作为字符串结束的标志符, 防止出现一些越界访问的错误, 可是字符串以\0结尾是c语言规定的和文件有关系吗?

没关系, 文件中的字符串不是以\0结尾的往文件中写入的时候只需要字符串的有效内容就可以, 除非就想往文件中写入\0不然不要在这里的第三个参数+1.

再介绍一个标志位O_APPEND, 如果想要在文件的尾部插入内容, 达到fopen中"a"的效果, 就要将open函数第二个参数O_TRUNC替换为O_APPEND.

在刚才的基础上追加了一遍原来的内容.

所以标记位 O_WRONLY|O_APPEND|O_CREAT 组合到一起就是c语言中fopen中a的功能


read

既然可以将缓冲区(数组)里面的内容通过write函数输出到文件里面, 那么这里也可以通过read函数读取文件里面的内容并放到缓冲区里面, read函数的参数如下:

与write函数相似,

第一个参数fd表示要读取哪个文件的内容.

第二个参数buf表示将读取的内容放入程序的哪个缓冲区中.

第三个参数count表示你要读取多少个字节的内容.

read函数的返回值表示如果读取成功了就返回读取的字符个数, 如果读取失败了或者没有内容就返回0.

read函数的第二个参数类型是void*, 表明read函数在读取内容的时候也没有数据类型的概念,不管文件里面装的是图片还是视频还是一些文本数据等等, 它读的都是二进制数据, 这些数据具体如何处理那都是使用者自己决定的.

比如:

使用read函数读取文本中的数据, 因为这里采用的是系统提供的函数读取数据, 并且我们想让数据以字符串的形式放入到数组里面, 所以read函数里面的读取字符的个数得是sizeof(buffer)-1留下来一个空间以免缓冲区满了装不下\0, 读取完数据之后就要在缓冲区的有效内容的后面手动添加一个\0用来表示此时的数据内容是字符串.

把刚才写入的内容再读出来并打印. 


close

close函数就是用来关闭open函数打开的文件的, 这个函数的参数如下:

将文件描述符传给close函数就可以.

所以其实fopen fclose fwrite fread fseek等函数在底层其实都是用操作系统提供的接口实现的, 这些函数与open close write read lseek函数一一对应.


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

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

相关文章

Leetcode每日一题学习训练——Python3版(从二叉搜索树到更大和树)

版本说明 当前版本号[20231204]。 版本修改说明20231204初版 目录 文章目录 版本说明目录从二叉搜索树到更大和树理解题目代码思路参考代码 原题可以点击此 1038. 从二叉搜索树到更大和树 前去练习。 从二叉搜索树到更大和树 给定一个二叉搜索树 root (BST)&#xff0c;请…

麦田医学CEO参加2023年度苏州市青年创业标兵授奖仪式

麦田医学CEO参加2023年度苏州市青年创业标兵授奖仪式 2023年12月4日&#xff0c;麦田&#xff08;苏州&#xff09;医学科技有限公司&#xff08;下简称麦田医学&#xff09;首席执行官&#xff08;CEO&#xff09;李任远同志受邀参加在苏州广电总台举行的2023年度苏州大学生创…

如何在亚马逊平台上找到最畅销的产品

这是您掌握在全球最大的在线市场上销售艺术的首选资源。在本博客中&#xff0c;我们将深入探讨在英国亚马逊上查找最畅销产品的秘密。在浩瀚的选择海洋中导航可能会令人不知所措&#xff0c;但不要害怕——有了正确的策略&#xff0c;您就可以发现利润丰厚的机会并提高销售额。…

C++ day53 最长公共子序列 不相交的线 最大子序和

题目1&#xff1a;1143 最长公共子序列 题目链接&#xff1a;最长公共子序列 对题目的理解 返回两个字符串的最长公共子序列的长度&#xff0c;如果不存在公共子序列&#xff0c;返回0&#xff0c;注意返回的是最长公共子序列&#xff0c;与前一天的最后一道题不同的是子序…

uniapp 在线预览PDF

1、官网地址&#xff1a; https://mozilla.github.io/pdf.js/getting_started/ 2、解压文件到static中 3、定义查看组件FilePreview <template><view><web-view :src"allUrl"></web-view></view> </template><script> e…

(04730)电路分析基础之电阻、电容及电感元件

04730电子技术基础 语雀&#xff08;完全笔记&#xff09; 电阻元件、电感元件和电容元件的概念、伏安关系&#xff0c;以及功率分析是我们以后分析电 路的基础知识。 电阻元件 电阻及其与温度的关系 电阻 电阻元件是对电流呈现阻碍作用的耗能元件&#xff0c;例如灯泡、…

mongoose学习记录

mongoose安装和连接数据库 npm i mongoose导入mongoose const mongoose require(mongoose) mongoose.set("strictQuery",true)连接数据库 mongoose.connect(mongodb:127.0.0.1:27017/test)设置回调 mongoose.connection.on(open,()>{console.log("连接成…

弱口令防护和网站防盗链有什么用

弱口令防护主要针对用户账户的安全。弱口令是指容易被猜测或破解的密码&#xff0c;如常见的密码、简单的数字序列或字典中的单词等。弱口令防护的目的是防止恶意用户或攻击者通过猜测或暴力破解密码的方式获取合法用户的账户权限。通过实施强密码策略、密码复杂度要求和账户锁…

centos 7.9 二进制部署 kubernetes 1.27.7

文章目录 1. 预备条件2. 基础配置2.1 配置root远程登录2.2 配置主机名2.3 安装 ansible2.4 配置互信2.5 配置hosts文件2.6 关闭防firewalld火墙2.7 关闭 selinux2.8 关闭交换分区swap2.9 修改内核参数2.10 安装iptables2.11 开启ipvs2.12 配置limits参数2.13 配置 yum2.14 配置…

【JavaEE进阶】 Spring核⼼与设计思想

文章目录 &#x1f332;Spring 是什么&#xff1f;&#x1f384;什么是IoC呢&#xff1f;&#x1f388;传统程序开发&#x1f388;传统程序开发的缺陷&#x1f388;如何解决传统程序的缺陷&#xff1f;&#x1f388;控制反转式程序开发&#x1f388;对⽐总结规律 &#x1f340;…

十二、FreeRTOS之FreeRTOS任务相关API函数

本节需要掌握以下内容&#xff1a; 1&#xff0c;FreeRTOS任务相关API函数介绍&#xff08;熟悉&#xff09; 2&#xff0c;任务状态查询API函数实验&#xff08;掌握&#xff09; 3&#xff0c;任务时间统计API函数实验&#xff08;掌握&#xff09; 4&#xff0c;课堂总结…

【鸿蒙应用开发】开发环境搭建及IDE安装使用

1.下载安装包 安装包下载地址&#xff1a; 点击跳转下载页面 可以根据自己的操作系统选择对应版本下载。 本文以Windows安装为例&#xff0c;Mac安装方式相同 2. 安装 下载好后&#xff0c;打开安装包&#xff0c;进入安装界面&#xff1a; 点击Next&#xff0c;进入安…

vue创建项目,使用可视化界面安装插件

安装项目&#xff1a; vue create vue-app 选择默认配置就行&#xff0c;也可以按需选择自定义配置 vue ui通过可视化管理项目 通过可视化安装全家桶插件

Spring Cloud 配置 Druid(二)

不废话&#xff0c;直接上代码&#xff0c; Nacos搭建的微服务&#xff0c;可以看Spring Cloud 配置 Nacos&#xff08;一&#xff09;-CSDN博客 一&#xff0c;pom文件 spring-cloud-starter-alibaba-nacos-discovery 和 spring-cloud-starter-openfeign 都是基于spring-cl…

95所双一流高校参与,“搜索界奥林匹克”决出28个获奖团队

只需要回答几个问题&#xff0c;就能生成个性化的简历&#xff0c;还提供优化建议&#xff0c;安排AI模拟面试。这样的效率神器&#xff0c;就出现第二届百度搜索创新大赛的赛场上。 &#x1f680; 来自南京航空航天大学的“肝到凌晨”团队&#xff0c;利用文心一言插件平台“…

【新手解答8】深入探索 C 语言:递归与循环的应用

C语言的相关问题解答 写在最前面问题&#xff1a;探索递归与循环在C语言中的应用解析现有代码分析整合循环示例代码修改注意事项结论 延伸&#xff1a;递归和循环的退出条件设置解析使用递归使用循环选择适合的方法 写在最前面 一位粉丝私信交流&#xff0c;回想起了当初的我C…

ORACLE使用Mybatis-plus批量插入

ORACLE使用mybatis-plus自带的iservice.saveBatch方法时&#xff0c;会报DML Returing cannot be batch错误&#xff1a; 推测原因是oracle不支持insert into table_name (,) values &#xff08;&#xff0c;&#xff09;,&#xff08;&#xff09;的写法。且oracle不会自动生…

【C语言】超详解,让你C语言成功入门(五)——操作符

目录 1.算术操作符2.移位操作符2.1左移操作符<<2.2右移操作符>> 3.位操作符4.赋值操作符5.单目操作符5.1单目操作符介绍5.2sizeof 和 数组 6.关系操作符7.逻辑操作符8.条件操作符&#xff08;三目操作符&#xff09;9.逗号表达式10.下标引用、函数调用和结构体11.表…

基于DotNetty实现一个接口自动发布工具 - 通信实现

基于 DotNetty 实现通信 DotNetty : 是微软的 Azure 团队&#xff0c;使用 C#实现的 Netty 的版本发布。是.NET 平台的优秀网络库。 项目介绍 OpenDeploy.Communication 类库项目,是通信相关基础设施层 Codec 模块实现编码解码 Convention 模块定义约定,比如抽象的业务 Handle…

华为手环 8 五款免费表盘已上线,请注意查收

华为手环 8&#xff0c;作为一款集时尚与实用于一体的智能手环&#xff0c;不仅具备强大的功能&#xff0c;还经常更新的表盘样式&#xff0c;让用户掌控时间与健康的同时&#xff0c;也能展现自己的时尚品味。这不&#xff0c;12 月官方免费表盘又上新了&#xff0c;推出了五款…