【Linux】—— 在Linux上进行读写文件操作

news2024/11/24 11:23:06

前言:

  • 在之前,我已经对进程的相关知识进行了详细的介绍。本期开始,我们将要学习的是关于 “基础I/O”的知识!!!

目录

(一)C文件接口

 (二)系统文件I/O

1、接口介绍

2、代码示例

(三)总结


(一)C文件接口

首先,在正式进入本期主题之前,我先用C文件的接口带大家简单的回顾下,顺便带大家认识相关的接口函数等。

首先就是往文件里面进行写数据操作:

#include <stdio.h>
#include <string.h>

#define LOG "log.txt"

int main()
{
    FILE *fp = fopen(LOG , "w");

    if(!fp)
    {
        perror("fopen");
        return 1;
    }

    const char *msg = "hello bit!\n";
    int count = 5;
    while(count--)
    {
        //fputs(msg,fp);
        fwrite(msg, strlen(msg), 1, fp);
    }

    fclose(fp);
    return 0;
}

输出展示:

【解释说明】

  1. 上述代码简单的实现了打开文件、写入文本内容,并关闭文件。在系统中,提供了丰富的用于对文件进行操作的函数;
  2. 打开文件使用 fopen 函数以写入模式打开文件,返回一个文件指针 fp;
  3. 如果文件打开失败,perror 函数将输出错误信息到标准错误输出流。
  4. 其次使用fwrite函数将字符串msg通过文件指针fp写入文件(除了这个外还有很多)

首先就是读文件里面的数据操作:

#define LOG "log.txt"
 
int main()
{
  
   FILE *fp = fopen(LOG, "r");
   if(!fp)
   {
     perror("fopen");
     return -1;
    }
    //正常进行文件操作
    while(1)
    {
      char line[128];
      if(fgets(line, sizeof(line), fp) == NULL) break;
      else printf("%s", line);
    }

    fclose(fp);
    return 0;
}

输出展示:

【解释说明】

  • 同样的对于读文件操作,在系统内部也提供的很多的函数去进行实现!

如上,是我们之前学的文件相关操作。还有 fseek ftell rewind 的函数。


 (二)系统文件I/O

操作文件,除了上述C接口(当然,C++也有接口,其他语言也有),我们还可以采用系统接口来进行文件访问.

先来直接以代码的形式,实现和上面一模一样的代码(写操作):

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main()
{
    umask(0);
    int fd = open("myfile", O_WRONLY|O_CREAT, 0644);
    if(fd < 0){
        perror("open");
    return 1;
    }
    int count = 5;
    const char *msg = "hello bit!\n";
    int len = strlen(msg);
    while(count--){
        write(fd, msg, len);
        //fd: 后面讲, msg:缓冲区首地址, len: 本次读取,期望写入多少个字节的数据。 
        //返回值:实际写了多少字节数据
    }
    close(fd);
    return 0;
}
  • C++中对文件进行读操作可写成下述:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main()
{
    int fd = open("myfile", O_RDONLY);
    if(fd < 0){
        perror("open");
        return 1;
    }
    const char *msg = "hello bit!\n";
    char buf[1024];
    while(1){
        ssize_t s = read(fd, buf, strlen(msg));//类比write
        if(s > 0){
            printf("%s", buf);
        }
        else{
            break;
         }
    }
    close(fd);
    return 0;
}

1、接口介绍

接下来,我首先带大家认识相关的接口。随后大家在来理解上述这两段代码!!

  • 最重要的当然是 open() ,通过对它的学习,我们将极大程度的理解有些知识

【解释说明】

参数

  • path:要打开的文件的路径字符串。
  • flags:打开文件的标志,可以使用一或多个以下标志的位或运算符 |

  第一个参数很好理解,对于第二个参数大家可能存在些疑惑我在这里重点讲讲关于这个标志的问题。

💨 首先,引入一个问题:OS是如何让用户给自己传递标志位的呢?

接下来,我给大家写个简单的 demo 样例帮助大家理解上述逻辑:

#include <stdio.h>

#define ONE 0x1
#define TWO 0x2
#define THREE 0x4
#define FOUR 0x8
#define FIVE 0x10

// 0000 0000 0000 0000 0000 0000 0000 0000
void Print(int flags)
{
    if(flags & ONE) printf("hello 1\n"); //充当不同的行为
    if(flags & TWO) printf("hello 2\n");
    if(flags & THREE) printf("hello 3\n");
    if(flags & FOUR) printf("hello 4\n");
    if(flags & FIVE) printf("hello 5\n");
}


int main()
{
    printf("--------------------------\n");
    Print(ONE);
    printf("--------------------------\n");
    Print(TWO);
    printf("--------------------------\n");
    Print(FOUR);
    printf("--------------------------\n");

    Print(ONE|TWO);
    printf("--------------------------\n");

    Print(ONE|TWO|THREE);
    printf("--------------------------\n");

    Print(ONE|TWO|THREE|FOUR|FIVE);
    printf("--------------------------\n");

    return 0;
}

输出展示:

 【解释说明】

  1. 上述代码展示了使用位运算来模拟标志位。在这个示例中,每个标志位都表示一种不同的行为,当相应的位被设置时,相关的行为会执行;
  2. 首先,定义了一组宏来表示不同的标志位,每个标志位都对应一个唯一的二进制位。例如,ONE的二进制表示是:0000 0000 0000 0000 0000 0000 0000 0001TWO的二进制表示是:0000 0000 0000 0000 0000 0000 0000 0010,依此类推。
  3. 接下来,定义了一个Print函数,它接受一个整数参数flags,这个参数表示一组标志位的组合。在函数内部,使用位运算和按位与操作符&来检查每个标志位是否被设置。

有了上述认识,大家在返回去看 open() 函数中的 flags参数,我想就很明显了。当我们在man手册中往下面翻的时候就会看到如下内容:

  • 这一个个的选项就相当于宏,我们只需关于宏函数内部的意义即可!

2、代码示例

接下来,我们通过写代码的方式来进行理解!!

首先,有如下代码示例:

int main()
{
   int fd = open(LOG,O_WRONLY);
   if(fd == -1)
   {
      printf("fd: %d, errno: %d, errstring: %s\n", fd, errno, strerror(errno));
   }
   else printf("fd: %d, errno: %d, errstring: %s\n", fd, errno, strerror(errno));
 
   close(fd);
   return 0;
 }
 

输出展示:

【解释说明】

  1. 上述代码的主要目的是打开一个文件并检查是否成功打开。如果打开失败,它将输出打开文件描述符(fd)、错误代码(errno)和错误字符串(strerror(errno));
  2. 然而,需要注意的是,因为开始并没有提供LOG这个文件,因此最后的输出肯定是发生报错。

解决方法就是在我们 open 的时候,再加上 【o_CREAT】这个标志:

输出展示:

然而,此时出现了一个奇怪的现象,我们通过查看得知 log.txt 文件的权限是处于乱码的情况:


因此,基于上述情况的出现。我们一般在用的时候一般不用 带两个参数的 open() ,而是用带三个参数的open() 函数

【解释说明】

  1. mode 是一个mode_t类型的参数,用于设置文件的权限;
  2. 它指定了文件的访问权限位,并且只有在使用O_CREAT标志创建文件时才会生效;
  3. 通常使用8进制表示权限位。例如,0644表示文件所有者具有读写权限,其他用户只有读权限。

基于上述情况,我们在后面加上相应的权限(我这里加的是0666):

输出展示: 

【解释说明】

  • 请注意,文件权限可能会受到操作系统的默认配置或其他因素的影响,即 umask;

  •  此时,系统默认的 umask 为2,因此在某些情况下,系统可能会对文件权限进行适当的修改,以使其符合操作系统的权限策略。

那么要如何保障这里的权限不受系统的影响呢?—— 我们可以自己设置

  • 此时,我们又需要引入一个新的函数:

接下来,我们对代码进行修改操作: 

输出展示:

【注意】

  • open 函数具体使用哪个,和具体应用场景相关,如目标文件不存在,需要open创建,则第三个参数表示创建文件的默认权限,否则,使用两个参数的open。

接下来,我们就需要往文件中写入数据了。在C++中,系统提供 write() 函数来进行写操作。

代码展示:

输出展示:


上述完成写入数据,接下来就是从文件中读出数据。在C++中,系统提供了 read() 函数

man手册查询:

代码展示:

输出展示:

【小结】

  • 有了上述这些认识,在回过头去看我给出的 读和写 的代码就容易了!

(三)总结

上面的 fopen fclose fread fwrite 都是C标准库当中的函数,我们称之为库函数(libc);


open close read write lseek 都属于系统提供的接口,称之为系统调用接口


回忆一下我们讲操作系统概念时,画的一张图:

  1. 根据上述图片,我们可以知道系统调用接口和库函数的关系,一目了然。
  2. 所以,可以认为,f#系列的函数,都是对系统调用的封装,方便二次开发。

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

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

相关文章

git中无法使用方向键的问题

windows下使用git命令行执行react脚本安装&#xff0c;发现无法使用上下键来去选中选项。最后只能换成cmd命令执行&#xff0c;发现可以上下移动以选中需要的选项。 bash命令行&#xff1a;移动光标无法移动选项 cmd命令行

为职场注入新活力,中国人民大学与加拿大女王大学金融硕士项目伴你追光而行

在金融职场从业多年的你&#xff0c;是否觉得有点疲惫呢&#xff0c;踏入职场一路过关闯将走到了今天&#xff0c;居于中高层管理的你是否需要注入新的能量呢&#xff0c;中国人民大学与加拿大女王大学金融硕士项目为你带来全新的课程体验&#xff0c;伴你追光而行。 中国人民大…

GitHub项目管理详细教程/git教程【有图有代码】

GitHub项目管理详细教程/git教程【有图有代码】 一、Git 基本操作二、Git 配置1、配置个人的用户名称和电子邮件地址2、查看配置信息 三、Git 工作区、暂存区和版本库四、上传自己的项目到GitHub仓库第一次第二次分支操作 在使用GitHub进行项目管理的之前&#xff0c;首先需要自…

【Java实习评审】对推电影详情模块的功能扩展预期有一定的代码实现

大家好&#xff0c;本篇文章分享【校招VIP】免费商业项目“推电影”第一期电影详情模块Java同学的代码周最佳作品。该同学来【安庆师范大学】“电子信息”专业。 1、本项目是基于年轻人的喜好&#xff0c;更个性的电影推荐网站。筛选各分类的知名电影&#xff0c;并给出推荐理…

vue3学习源码笔记(小白入门系列)------ 重点!响应式原理 代码逐行分析

目录 备注响应式数据创建ref 和 reactive 核心 作用第一轮的 依赖收集 发生时机setup 阶段 去更改了 响应式数据 会发生依赖收集吗 派发更新派发更新是什么时候 触发的&#xff1f;扩展&#xff1a; setup阶段 响应式数据被修改 会触发组件更新吗 vue 是如何根据派发更新来触发…

第26章_瑞萨MCU零基础入门系列教程之独立看门狗定时器-IWDT

本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写&#xff0c;需要的同学可以在这里获取&#xff1a; https://item.taobao.com/item.htm?id728461040949 配套资料获取&#xff1a;https://renesas-docs.100ask.net 瑞萨MCU零基础入门系列教程汇总&#xff1a; ht…

《经营者集中反垄断合规指引》发布,合规管理平台助力企业合规建设

近日&#xff0c;《经营者集中反垄断合规指引》的发布为企业合规建设提供了更具体和明确的指导。在这一新形势下&#xff0c;道本科技智慧合规管理平台作为一项强大的工具&#xff0c;成为企业实现合规建设的重要支持。本文将重点介绍智慧合规管理平台&#xff0c;探讨其对企业…

LeetCode算法心得——和可被 K 整除的子数组(前缀和+HashMap)

大家好&#xff0c;我是晴天学长&#xff0c;同余定理的应用&#xff0c;需要的小伙伴可以关注支持一下哦&#xff01;后续会继续更新的。 1) .和可被 K 整除的子数组 题目描述 给定一个整数数组 A&#xff0c;返回其中元素之和可被 K 整除的&#xff08;连续、非空&#xff0…

如何在matlab绘图的标题中添加变量?变量的格式化字符串输出浅析

文章目录 matlab的格式化输出控制符字段宽度、精度和对齐方式的控制matlab的格式化输出总结 matlab的格式化输出控制符 Matlab在画图的时候&#xff0c;采用title函数可以增加标题&#xff0c;该函数的输入是一个字符串&#xff0c;有时候我们想在字符串中添加一些变量&#x…

uni-app:标签中对数据进行判断,看数据前中后是否含有需要的字符startsWith(),endsWith(),includes()

效果图 核心代码 判断数据是否存在并且此数据是否以‘-’开头 <image v-if"line && line.startsWith(-)" :src"img1" alt""></image> 判断数据是否存在并且此数据是不是以‘ing’结尾 <image v-if"line &&…

代码块的介绍

代码块 局部代码块 局部代码块&#xff0c;用大括号进行圈着&#xff0c;然后控制这个变量的内存占用时间&#xff0c;用完这个变量我们就回收&#xff0c;不占用多余空间。但是随着这个电脑的技术的发展&#xff0c;几个变量的定义对于内存那么大的电脑影响已经不大了。 构…

ubuntu 安装截图软件 flameshot

linux安装flameshot 1、去github下载对应deb版本 Releases flameshot-org/flameshot GitHub 2、先更新一次依赖 sudo apt-get install -f 3、安装依赖 # Compile-time apt install g cmake build-essential qt5-default qttools5-dev-tools libqt5svg5-dev qttools5-dev…

[Qt]控件

文章摘于 爱编程的大丙 文章目录 1. 按钮类型控件1.1 按钮基类 QAbstractButton1.1.1 标题和图标1.1.2 按钮的 Check 属性1.1.3 信号1.1.4 槽函数 1.2 QPushButton1.2.1 常用API1.2.2 按钮的使用 1.3 QToolButton1.3.1 常用API1.3.2 按钮的使用 1.4 QRadioButton1.4.1 常用API…

高压电缆护层接地环流及温度在线监测系统

高压电缆的金属护层是电缆的重要组成部分&#xff0c;当缆芯通过电流时&#xff0c;会在金属护层上产生环流&#xff0c;外护套的绝缘状态差、接地不良、金属护层接地方式不正确等等都会引起护套环流异常现象&#xff0c;严重威胁电缆运行安全。 当电缆金属护层环流出现异常时…

FFmpeg入门之Windows/Linux下FFmpeg源码编译

1.源码下载: git clone https://github.com/FFmpeg/FFmpeg.git windows : macos: ubuntu: 2.编译FFmpeg CompilationGuide – FFmpeg windows: 1.下载yasm并安装 : Download - The Yasm Modular Assembler Project 下载后复制到c:/windows 2.下载SDL 3.下载H264/265源码 git…

对缓存穿透、雪崩、击穿的理解,引入分布式锁

缓存实战 1、缓存穿透 先来了解一个小图&#xff0c; 1.1 概念&#xff1a; 缓存穿透指一个一定不存在的数据&#xff0c;由于缓存未命中这条数据&#xff0c;就会去查询数据库&#xff0c;数据库也没有这条数据&#xff0c;所以返回结果是 null。如果每次查询都走数据库&a…

Vue中的动态 Class Style

动态 Class & Style 我们平时可以直接给元素设置静态的 Class 或者是 Style&#xff0c;但是这种方式会带来很多限制&#xff0c;假设我想要内容动态的改变 Class 或者是 Style&#xff0c;通过原生的方式要通过 JavaScript 频繁操作 dom 才能够实现。而在 Vue 中我们无需…

java入坑之注解

一、注解入门 注解&#xff1a;Annotation 从JDK 1.5 引入位于源码中(代码/注释/注解)&#xff0c;使用其他工具进行处理的标签注解用来修饰程序的元素&#xff0c;但不会对被修饰的对象有直接的影响只有通过某种配套的工具才会对注解信息进行访问和处理 主要用途 提供信息给编…

【职场篇】五年游戏开发老兵,我为什么劝你学UE?

我是水曜日鸡&#xff0c;一个在游戏行业摸爬滚打了5年的行业老兵。在Unity和UE4各有两年半的开发经验。曾参与开发了索尼中国之星计划之一的 《硬核机甲》 项目&#xff0c;用的是Unity引擎。目前在上海某大厂参与研发 开放世界项目&#xff0c;用的是UE4引擎。今天我就来终结…

《重构改善代码设计》

文章目录 1.重构的原则2.代码的坏味道3.第一组重构3.1.提炼函数3.2.内联函数3.3.提炼变量3.4.内联变量3.5.修改函数名称3.6.封装变量3.7.变量改名3.8.引入参数对象3.9.函数组合成类3.10.函数组合成变换3.11.拆分阶段 4. 封装4.1. 封装记录4.2. 封装集合4.3. 以对象取代基本类型…