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语言中文件操作的各种特性。

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

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

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

相关文章

Spring Boot中使用Redis和Lua脚本实现延时队列

码到三十五 &#xff1a; 个人主页 延时队列是一种常见的需求。延时队列允许我们延迟处理某些任务&#xff0c;这在处理需要等待一段时间后才能执行的操作时特别有用&#xff0c;如发送提醒、定时任务等。文中&#xff0c;将介绍如何在Spring Boot环境下使用Redis和Lua脚本来实…

Java Web网页设计(5)-查看网页

青春就像一只容器 装满了不安 躁动 青涩 与偶尔的疯狂 5.下面开始做网页的查看 如何实现点击查看订单 即可显示已经添加的数据信息 调用doGet 1&#xff09;首先 修改一下名字 修改为工程名 2&#xff09;调用Dao返回一个集合 存到一个公共对象里面 3&#xff09;把集合显示到…

第一次用ssh登录树莓派or linux服务器出现Permission denied (publickey)

authenticity of host ) cant be established ssh userip Permission denied (publickey) 解决办法&#xff1a; 第一步&#xff1a; PasswordAuthentication yes 第二步&#xff1a; service sshd restart 这两步一步都不能少 注意&#xff01;

【UnityRPG游戏制作】NPC交互逻辑、动玩法

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;就业…

信息泄露.

一&#xff0c;遍历目录 目录遍历&#xff1a;没有过滤目录相关的跳转符号&#xff08;例如&#xff1a;../&#xff09;&#xff0c;我们可以利用这个目录找到服务器中的每一个文件&#xff0c;也就是遍历。 tipe&#xff1a;依次点击文件就可以找到flag 二&#xff0c;phpi…

栈的磁盘优化:降低存取成本的算法与实现

栈的磁盘优化&#xff1a;降低存取成本的算法与实现 问题背景简单实现方法的分析实现方法PUSH操作POP操作成本分析渐近分析 优化实现方法实现方法成本分析渐近分析 进一步优化&#xff1a;双页管理策略实现方法管理策略成本分析 伪代码示例C代码示例结论 问题背景 在具有有限快…

【JAVA基础之反射】反射详解

&#x1f525;作者主页&#xff1a;小林同学的学习笔录 &#x1f525;mysql专栏&#xff1a;小林同学的专栏 1.反射 1.1 概述 是在运行状态中&#xff0c;对于任意一个类&#xff0c;都能够知道这个类的所有属性和方法&#xff1b; 对于任意一个对象&#xff0c;都能够调用它…

15、ESP32 Wifi

ESP32 的 WIFI 功能是模块内置的&#xff0c;通过 ESP32 的基础库调用一些函数就可以轻松使用它。 Wifi STA 模式&#xff1a; 让 ESP32 连接附近 WIFI&#xff0c;可以上网访问数据。 // 代码显示搜索连接附近指定的 WIFI // 通过 pin 按键可断开连接#include <WiFi.h>…

C语言实现左旋字符串、左旋字符串找子串、杨氏矩阵找数字、 判断有序数列等介绍

文章目录 前言一、左旋字符串1. 左旋字符串12. 左旋字符串2 二、杨氏矩阵1. 结构体返回数字在杨氏矩阵中的位置2. 行列数字的地址返回数字在杨氏矩阵中的位置 三、一个字符串左旋能否得到另一个字符串1. 一个一个左旋并判断2. 使用库函数 四、判断有序数列总结 前言 C语言实现…

ubuntu修改/etc/resolve.conf总是被重置

ubuntu修改/etc/resolve.conf总是被重置 其实处理来很简单&#xff0c;根据英文提示删除/etc/resolve.conf,那是一个软链接&#xff0c;重新创建/etc/resolve.conf rm /etc/resolve.conf vi /etc/resolve.conf 添加nameserver 223.5.5.5

抖音TikTok34.5.3最新解锁全球绿色版

软件名称】TikTok 【软件版本】v34.4.5 【软件大小】173m 【适用平台】安卓 【软件简介】 TikTok是一款玩转音乐创意的短影音应用&#xff0c;更是年轻人的交友社群。在这里每个人都可以拍出 属于自己的创意影片&#xff0c;跟着音乐的节奏&#xff0c;你可以尽情拍 摄多种…

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

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

深度学习500问——Chapter08:目标检测(6)

文章目录 8.3.7 RetinaNet 8.3.7 RetinaNet 研究背景 Two-Stage 检测器&#xff08;如Faster R-CNN、FPN&#xff09;效果好&#xff0c;但速度相对慢。One-Stage 检测器&#xff08;如YOLO、SSD&#xff09;速度快&#xff0c;但效果一般。 作者对one-stage检测器准确率不高…

链表经典面试题下

目录 如有帮助&#xff0c;还望三连支持&#xff0c;谢谢&#xff01;&#xff01;&#xff01; 题目一&#xff1a;141. 环形链表 - 力扣&#xff08;LeetCode&#xff09; 题目二&#xff1a;142. 环形链表 II - 力扣&#xff08;LeetCode&#xff09; 题目三&#xff1a;…

为什么选择OpenNJet?OpenNJet下一代云原生应用引擎!OpenNJet开发实战!

前言导读 在当今这个数字化转型加速的时代&#xff0c;云原生技术已成为企业和开发者构建现代应用的首选路径。OpenNJet作为新一代云原生应用引擎&#xff0c;在国内外技术社区受到了广泛关注。 本文将深入探讨OpenNJet的特点、优势以及在开发实践中的应用&#xff0c;带您全…

Java 笔记 13:Java 数组内容,数组的声明、创建、初始化、赋值等,以及内存分析

一、前言 记录时间 [2024-05-03] 系列文章简摘&#xff1a; Java 笔记 01&#xff1a;Java 概述&#xff0c;MarkDown 常用语法整理 Java 笔记 02&#xff1a;Java 开发环境的搭建&#xff0c;IDEA / Notepad / JDK 安装及环境配置&#xff0c;编写第一个 Java 程序 Java 笔记 …

C++ | Date 日期类详解

目录 简介 日期类总代码 | Date 类的定义 & 构造 & Print 类的定义 构造函数 & Print 比较类&#xff0c;如<、>、<...... 值加减类&#xff0c;如、-、、-...... 加减类具体分类 判断某个月有多少天 GetMonthDay 日期类 / &#xff08;- / -&…

场景文本检测识别学习 day08(无监督的Loss Function、代理任务)

无监督的Loss Function&#xff08;无监督的目标函数&#xff09; 根据有无标签&#xff0c;可以将模型的学习方法分为&#xff1a;无监督、有监督两种。而自监督是无监督的一种无监督的目标函数可以分为以下几种&#xff1a; 生成式网络的做法&#xff0c;衡量模型的输出和固…

protobuf在配置文件管理上的应用

TextFormat::ParseFromString 是 Google Protocol Buffers&#xff08;通常简称为 Protobuf&#xff09;库中的一个函数&#xff0c;用于从文本格式解析消息。Protobuf 是一种用于序列化结构化数据的库&#xff0c;它允许你定义数据的结构&#xff0c;然后自动生成源代码来处理…

【实用推荐】7个靠谱赚钱软件,宅家也能轻松赚钱!

在数字化浪潮下&#xff0c;如何在家轻松赚取收益成为许多人关注的焦点。软件市场的蓬勃发展为我们提供了多种选择&#xff0c;但面对琳琅满目的赚钱应用&#xff0c;许多人感到无从下手&#xff0c;担心选择不当。本文将为您揭示这些软件背后的奥秘&#xff0c;助您找到最适合…