【Linux从入门到精通】文件操作(C语言vs系统调用)

news2024/11/23 18:34:56

 

文章目录

一、C语言的文件IO相关函数操作

1、1 fopen与fclose

1、2 fwrite

1、3 fprintf与fscanf

1、4 fgets与fputs

二、系统调用相关接口

2、1 open与close

2、2 write和read

三、简易模拟实现cat指令

四、总结


🙋‍♂️ 作者:@Ggggggtm 🙋‍♂️

👀 专栏:Linux从入门到精通  👀

💥 标题:文件操作💥

 ❣️ 寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景 ❣️ 

  本篇文章主要会讲解C语言的文件IO相关操作的函数,同时也会对Linux下的文件操作系统调用接口进行讲解。希望本篇文章会对你有所帮助。

一、C语言的文件IO相关函数操作

1、1 fopen与fclose

  fopen() 函数原型:FILE *fopen(const char *filename, const char *mode); 作用:打开一个文件,并返回一个文件指针。 参数:

  • filename:要打开的文件名(含路径)
  • mode:打开文件的模式,如 "r" 表示只读,"w" 表示写入(如果文件存在则清空内容),"a" 表示追加写入等。

  具体如下图:

  fclose() 函数原型:int fclose(FILE *stream); 作用:关闭一个打开的文件。 参数:

  • stream:要关闭的文件指针

   具体可结合下图理解:

  我们知道使用 fopen 时需要添加索要打开文件的路径。当我们以w的方式进行打开时,该文件不存在会自动创建文件,具体代码如下图:

#include<stdio.h>    
    
int main()    
{    
    FILE* fd = fopen("log.txt","w");    
    if(fd==NULL)    
    {    
        perror("fopen");    
    }    
    
    fclose(fd);  
    
    //while死循环完全是为了方便查看和观察
    while(1)
    {
        sleep(1);
    }                                                                                                                                        
    return 0;    
} 

  上述代码中,fopen中并没有添加路径,只有一个文件名字。那么能打开成功吗?其次是,当前目录下并没有 log.txt 文件,如果能打开成功,文件会被创建到哪里呢?我们带着这些疑问接着往下看。

  我们不妨先观察一下运行结果,如下图:

  我们看到确实能够出创建出来,也是创建在了当前目录了!这是为什么呢?当一个程序运行起来后,会在内存中创建相应的数据结构,同时变成进程。该进程包含了当前所在的工作目录,且还有当前的可执行文件所在的目录。具体如下图:

  所以即使我们并没有添加路径,操作系统也会知道当前所在的路径。并且默认创建到当前的工作路径下。

1、2 fwrite

  fwrite的函数原型:size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream)。用于将数据块按字节写入文件。参数:

  • ptr:指向要写入的数据的指针。
  • size:要写入的每个数据项的字节数。
  • count:要写入的数据项的数量。
  • stream:目标文件的指针。

  我们也可看下图理解:

  我们现在用fwrite向log.txt中写入,具体代码如下:

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

int main()
{
    FILE* fp = fopen("log.txt","w");
    if(fp==NULL)
    {
        perror("fopen");
    }
   //进行文件操作
   const char *s1 = "hello Linux\n"; 
   fwrite(s1, strlen(s1), 1, fp);

  
    fclose(fp);    
    return 0;
}

   这里有一个问题:在写入文件时,要不要把s1的‘\0’写入呢?答案是不用。字符串结尾标志'\0'只是C语言规定的。文件并不用遵守C语言的规则!我们看运行结果:

  log.txt文件中确实被写入了。假如我们注释掉写入的代码,只是打开后直接关闭文件,结果会是什么呢?如下图:

  文件内容为空了!!!为什么呢?原因是以“w”的方式打开文件,就是在写入前会被清空文件内容。 

1、3 fprintf与fscanf

  fprintf() 函数原型:int fprintf(FILE *stream, const char *format, ...); 作用:向文件中按指定格式写入数据。 参数:

  • stream:要写入的文件指针。
  • format:格式化字符串,类似于printf()函数的格式化参数。 返回值:成功写入的字符数,出错时返回负值。

  fprintf与printf相比,fprintf第一个参数是FILE* ,其他的都一样。只不过是输出到了指定的文件上。

  fscanf() 函数原型:int fscanf(FILE *stream, const char *format, ...); 作用:从文件中按指定格式读取数据。 参数:

  • stream:要读取的文件指针。
  • format:格式化字符串,类似于scanf()函数的格式化参数。 返回值:成功读取并匹配的项目数量,出错或到达文件结尾时返回EOF。

  fscanf() 与scanf() 相比,fscanf() 第一个参数是FILE* ,其他的都一样。读取数据时,是从指定的文件上读取。

  这里我们就举例说明fsacnf,我们想要把文件的内容读取并输出,代码如下:

#include<stdio.h>    
#include<unistd.h>    
#include<string.h>    
    
int main()    
{    
    FILE* fp = fopen("log.txt","r");    
    if(fp==NULL)    
    {    
        perror("fopen");    
    }    
        
    char line[128];    
    while(fscanf(fp,"%s",line) != EOF)    
    {                                                                                                                                                        
        printf("%s\n", line);    
    }   
    return 0;
} 

  运行结果如下:

 

  注意,当我们要读取内容是,要修改打开文件的方式,应该以“r”的方式打开文件。否则会出现意想不到的结果!!!

1、4 fgets与fputs

  fgets() 函数原型:char *fgets(char *str, int n, FILE *stream); 作用:从文件中读取一行字符串。 参数:

  • str:要读取的字符串存放的缓冲区。
  • n:最多读取的字符数(包括换行符)。
  • stream:要读取的文件指针。 返回值:成功时返回str,失败或到达文件结尾时返回NULL。

   具体如下图:

  fputs() 函数原型:int fputs(const char *str, FILE *stream); 作用:向文件中写入一个字符串。 参数:

  • str:要写入的字符串。
  • stream:要写入的文件指针。 返回值:成功写入的字符数,出错时返回EOF。

 具体如下图:

  我们结合下述实例来理解fgets和fputs的用法,代码如下:

#include<stdio.h>    
#include<unistd.h>    
#include<string.h>    
    
int main()    
{    
    FILE* fp = fopen("log.txt","r");    
    if(fp==NULL)    
    {    
        perror("fopen");    
    }     
    char line[64];
    //fgets -> C -> s(string) -> 会自动在字符结尾添加\0
    while(fgets(line, sizeof(line), fp) != NULL)                                                                                                             
    {
        //printf("%s", line);
        fputs(line, stdout); //输出到屏幕上
    }
    fclose(fp);
    return 0;
} 

​

   运行结果如下:

二、系统调用相关接口

2、1 open与close

   open()函数:open函数用于打开文件并获取文件描述符。它接受一个文件路径和一组标志作为参数,并返回一个用于后续文件操作的文件描述符。函数原型:int open(const char *pathname, int flags, mode_t mode)。详细解释:

  • 函数说明:打开文件并获取文件描述符。
  • 参数:
    • pathname:要打开的文件路径。
    • flags:打开文件的标志,例如O_RDONLY(只读)、O_WRONLY(只写)、O_RDWR(读写)等。
    • mode:在创建新文件时使用的权限位。
  • 返回值:
    • 成功:返回一个非负整数,表示文件描述符
    • 失败:返回-1,并设置errno来指示错误。

  具体可结合下图理解:

  有很多的选项,我们想要添加那个选项,只需要在第二个参数 按位与(‘|’) 上就行。为什么 按位与(‘|’)呢?这里涉及到了位图的知识。想要知道的可以去了解一下位图。

  close()函数:close函数用于关闭打开的文件。它接受文件描述符作为参数,并返回一个表示成功与否的状态值。   函数原型:int close(int fd)。详细解释:

  • 函数说明:关闭打开的文件。
  • 参数:
    • fd:要关闭的文件描述符。
  • 返回值:
    • 成功:返回0。
    • 失败:返回-1,并设置errno来指示错误。

  我们通过如下实例来理解open和close。代码如下:

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

    
int main()    
{    
      int fd1 = open("log.txt", O_RDONLY);
      int fd2 = open("log2.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666); //rw-rw-rw-
      if(fd1 < 0 || fd2 < 0)
      {
          perror("open");                                                                                                                                  
          return 1;
      }
      close(fd1);
      close(fd2);

      return 0;
} 

  运行结果如下:

  确实打开成功了。为什么log2.txt与我们设置的权限并不相同呢?不要忘记了系统中还有umask掩码。

2、2 write和read

  write()函数:write函数用于向文件中写入数据。它接受文件描述符、要写入的数据和字节数作为参数,并返回实际写入的字节数。函数原型:ssize_t write(int fd, const void *buf, size_t count)。详细解释:

  • 函数说明:向文件中写入数据。
  • 参数:
    • fd:要写入的文件描述符。
    • buf:要写入的数据的缓冲区。
    • count:要写入的字节数。
  • 返回值:
    • 成功:返回实际写入的字节数。
    • 失败:返回-1,并设置errno来指示错误。

  read()函数:read函数从文件中读取数据。它接受文件描述符、缓冲区指针和要读取的字节数作为参数,并返回实际读取的字节数。函数原型:ssize_t read(int fd, void *buf, size_t count)。详细解释:

  • 函数说明:从文件中读取数据。
  • 参数:
    • fd:要读取的文件描述符。
    • buf:用于存储读取数据的缓冲区。
    • count:要读取的最大字节数。
  • 返回值:
    • 成功:返回实际读取的字节数。
    • 失败:返回-1,并设置errno来指示错误。

  write和read用起来也相对简单。这里就不再举例详细解释说明了。 

三、简易模拟实现cat指令

  我们知道,cat是打印出一个文件的内容。我们学习了文件操作后,就来简单的模拟实现一下cat指令。

  cat指令不就是接受到文件,然后打印出文件的内容吗。这好像就是我们刚刚学了文件操作。我们直接看代码:

#include<stdio.h>    
#include<unistd.h>    
#include<string.h>
int main(int argc,char* argv[])
{    
    if(argc != 2)     
    {    
        printf("argv error!\n");    
        return 1;    
    }    
    FILE *fp = fopen(argv[1], "r");     
    if(fp == NULL)    
    {    
        //strerror    
        perror("fopen");    
        return 2;    
    }    
    
    //按行读取                                                                                                                                               
    char line[64];    
    //fgets -> C -> s(string) -> 会自动在字符结尾添加\0 
    // 将文件的内容打印到屏幕上   
    while(fgets(line, sizeof(line), fp) != NULL)    
    {    
        //printf("%s", line);    
        fprintf(stdout, "%s", line); //fprintf->stdout?
    }
    fclose(fp);
    return 0;
}

  在运行时加上文件名就可以打印出文件的内容了。再加上我们之前讲到的创建子进程进行程序替换实现的简易版的shell,不就是实现了cat指令嘛!!!我们看输出结果:

四、总结

  本篇文章讲述了一系列的文件操作函数。其实我们学的C语言的文件操作函数,底层都是封装的系统调用的接口。因为我们对文件的写入和读取,不就是对硬盘的写入和读取吗!文件可是放在硬盘上的。语言想要访问硬件设备,必须通过操作系统!!! 

  每套语言都是有自己的文件操作函数,底层都是封装的系统调用的接口。但是操作系统不只是有Linux,还有windows等等。那语言就是封装所有的操作系统的接口呗。只不过是在调用时会有选择判断。这样封装后,语言就有了跨平台性。

  上文中有一个名词:文件描述符。我们并没有对此进行详解。下篇文章会对此进行讲解。这个也是一个重点!!!

  本片文章的讲解就到这里。感谢阅读ovo~ 

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

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

相关文章

AP2915DC-DC降压恒流驱动IC LED电源驱动芯片 汽车摩托电动车灯

AP2915 是一款可以一路灯串切换两路灯串的降压 恒流驱动器,高效率、外围简单、内置功率管&#xff0c;适用于 5-80V 输入的高精度降压 LED 恒流驱动芯片。内置功 率管输出功率可达 12W&#xff0c;电流 1.2A。 AP2915 一路灯亮切换两路灯亮&#xff0c;其中一路灯亮可 以全亮&a…

C++,文本文件,读取文件

代码演示&#xff1a; #include<iostream> using namespace std; #include<string> #include<fstream>void test() {//1、包含头文件//2、创建流对象ifstream ifs;//3、打开文件并判断文件是否成功ifs.open("test.txt", ios::in);if (!ifs.is_ope…

问道管理:A股缩量整理 新股上演久违暴涨模式

周三&#xff0c;大盘低开后震动&#xff0c;三大指数小幅跌落&#xff0c;创业板指相对偏强。 早盘开盘后&#xff0c;沪指、深证成指弱势震动&#xff0c;创业板指探底上升翻红&#xff0c;盘面热门乏善可陈。午后三大指数震动走弱&#xff0c;创业板指再度翻绿。医药板块活…

Vue 实现重定向、404和路由钩子(六)

一、重定向 1.1 修改 Main.vue <template><div><el-container><el-aside width"200px"><el-menu :default-openeds"[1]"><el-submenu index"1"><template slot"title"><i class"…

伪原创神码ai怎么样【php源码】

这篇文章主要介绍了python汉化补丁包下载&#xff0c;具有一定借鉴价值&#xff0c;需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获&#xff0c;下面让小编带着大家一起了解一下。 火车头采集ai伪原创插件截图&#xff1a; ** Spyder汉化&#xff08;python汉化&…

在vue项目使用数据可视化 echarts ,柱状图、折线图、饼状图使用示例详解及属性详解

官网地址&#xff1a;Apache ECharts ​一、下载插件并在页面中引入 npm install echarts --save 页面导入&#xff1a; import * as echarts from echarts 全局导入&#xff1a; main.js 中&#xff0c;导入并注册到全局 import echarts from echarts Vue.prototype.$echart…

【云存储】【腾讯云】【阿里云】【b2】【google drive】【one drive】【s3】【azure】对比

【1】google drive 【2】b2 price 【3】腾讯云对象存储 文档中心 > 对象存储 > 开发者指南 > 对象 > 存储类型 > 存储类型概述 文档中心 > 对象存储 > 购买指南 > 计费项 > 数据取回费用

【计算机组成原理】24王道考研笔记——第四章 指令系统

第四章 指令系统 一、指令系统 指令是指示计算机执行某种操作的命令&#xff0c;是计算机运行的最小功能单位。一台计算机的所有指令的集合构成该 机的指令系统&#xff0c;也称为指令集。 指令格式&#xff1a; 1.1分类 按地址码数目分类&#xff1a; 按指令长度分类&…

AttentionFreeTransformer 源码解析(一):AFTFull、AFTSimple、AFTLocal

我觉得源码写的很好懂&#xff0c;我就不加注释了&#xff0c;直接上计算流程图。 AFTFull class AFTFull(nn.Module):def __init__(self, max_seqlen, dim, hidden_dim64):super().__init__()max_seqlen: the maximum number of timesteps (sequence length) to be fed indim…

echarts柱状图X轴增加table列表显示数据,多y轴

效果图 完整配置 data(){return{chart1:null,chartType1:1,data:{years:{date:[2015,2016,2017,2018,2019,2020,2021,2022,2023],business:[10,23,26,33,43,58,50,45,66],profit:[3,4,6,7,8,5,7,8,12],proportion:[12,8,15,20,12,16,13,15,9]},months:{date:[1月, 2月,3月, 4月…

在指定的 DSN 中,驱动程序和应用程序之间的体系结构不匹配

1.Cadence 17.2 配置CIS数据库报&#xff1a;ERROR(ORCIS-6245): Database Operation Failed 安装cadance17.2以上版本时&#xff0c;ERROR(ORCIS-6245): Database Operation Failed_收湾湾的博客-CSDN博客 原因是ODBC数据库没有配置&#xff0c;或者没有驱动&#xff0c; 驱…

侯捷 C++ part2 兼谈对象模型笔记——3 模板

3 模板 3.1 类模板/函数模板 补充&#xff1a;只有模板的尖括号中<>&#xff0c;关键字 typename 和 class 是一样的 3.2 成员模板 它即是模板的一部分&#xff0c;自己又是模板&#xff0c;则称为成员模板 其经常用于构造函数 ctor1 这是默认构造函数的实现&#…

阿里云服务器免费申请使用限制条件及云主机配置

阿里云服务器免费试用申请链接入口&#xff0c;阿里云个人用户和企业用户均可申请免费试用&#xff0c;最高可以免费使用3个小时&#xff0c;阿里云服务器网分享阿里云服务器免费试用申请入口链接及云服务器配置&#xff1a; 目录 阿里云服务器免费试用 企业用户免费服务器试…

解决Qt的列表加载大量数据卡顿的问题

问题概述 本人在使用QListView插入大量数据时&#xff0c;界面卡顿十分严重。数据量大概只有上千左右&#xff0c;但是每个Item的内容比较多。当数据不停地插入一段时间后&#xff0c;卡顿到鼠标的移动都有点困难。 解决思路 QListView是典型的MVC思想的产物。界面呈现出来的数…

CorelDRAW(CDR) 2023中文版64位下载新功能教程

CorelDRAW2023&#xff08;简称CDR2023&#xff09;是一款非常专业的图形设计工具&#xff0c;该产品推出了全新的2023版本&#xff0c;在功能和体验上更进一步&#xff0c;最新的填充和透明设备功能可以完全控制任何类型的纹理&#xff0c;适用于网络摄影、印刷项目、艺术、排…

G. Counting Graphs Codeforces Round 891 (Div. 3) 1857G

Problem - G - Codeforces 题目大意&#xff1a;给出一棵n个点的边权树&#xff0c;问有多少个边权最大不超过s的图的最小生成树是这棵树 2<n<2e5;1<w[i]<1e9 思路&#xff1a;对于最小生成树上的每一条边&#xff0c;如果我们在包含这条边的链上的两点之间加了…

SpringBoot 该如何预防 XSS 攻击

XSS 漏洞到底是什么&#xff0c;说实话我讲不太清楚。但是可以通过遇到的现象了解一下。在前端Form表单的输入框中&#xff0c;用户没有正常输入&#xff0c;而是输入了一段代码&#xff1a;</input><img src1 onerroralert1> 这个正常保存没有问题。问题出在了列表…

建设数字化工厂管理系统的必要性有哪些

随着科技的不断发展&#xff0c;数字化已经深入到各个行业和领域&#xff0c;其中包括制造业。数字化工厂管理系统作为一种先进的生产管理模式&#xff0c;能够提高生产效率&#xff0c;降低生产成本&#xff0c;提升企业的竞争力。下面&#xff0c;我们就来探讨一下建设数字化…

Mysql按小时进行分组统计数据

目录 前言 按1小时分组统计 按2小时分组统计 按X小时分组统计 前言 统计数据时这种是最常见的需求场景&#xff0c;今天写需求时发现按2小时进行分组统计也特别简单&#xff0c;特此记录下。 按1小时分组统计 sql&#xff1a; select hour(pass_time) …

自建hexo博客并将原有的文章发布其上

1、保存粘贴到memo9中的博客文章&#xff0c;并将txt转换成word文档 varPowerShellPath, CommandLine: string; // , ScriptPath begin//save to txtMemo9.Lines.SaveToFile(test.txt);memo10.Lines.SaveToFile(txt2word.ps1);//save as docxPowerShellPath : powershell.exe…