【Linux系统编程】第二十六弹---彻底掌握文件I/O:C/C++文件接口与Linux系统调用实践

个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】【Linux系统编程】

目录

1、回顾C语言文件接口

1.1、以写的方式打开文件

1.2、以追加的方式打开文件

2、初步理解文件

2.1、C++文件接口

3、进一步理解文件

3.1、系统调用实现写方式打开文件

3.2、系统调用实现追加打开文件

 3.3、理解open第二个参数原理


1、回顾C语言文件接口

1.1、以写的方式打开文件

1、如果文件不存在,就在当前路径下新建指定的文件。
2、默认打开文件的时候,会先清空文件 ->  等价于 >输出重定向。

代码演示一

#include<stdio.h>int main()
{// 以写方式打开文件FILE* fd = fopen("log.txt","w");if(fd == NULL) {perror("fopen");return 1;}// 向文件写内容fprintf(fd,"helloworld,%d,%s,%lf\n",10,"abcd",3.14);// 关闭文件fclose(fd);return 0;
}

运行结果 

 

代码演示二 

#include<stdio.h>int main()
{// 以写方式打开文件FILE* fd = fopen("log.txt","w");if(fd == NULL) {perror("fopen");return 1;}fclose(fd);return 0;
}

运行结果 

看一段命令

[jkl@host file]$ cat log.txt
helloworld,10,abcd,3.140000
[jkl@host file]$ echo "hello linux" > log.txt
[jkl@host file]$ cat log.txt
hello linux
[jkl@host file]$ > file.txt
[jkl@host file]$ ls
file.txt  log.txt  makefile  myfile  myfile.c
[jkl@host file]$ cat log.txt
hello linux
[jkl@host file]$ >log.txt
[jkl@host file]$ cat log.txt
[jkl@host file]$ 

解析命令

结论:

重定向 > 可以创建新文件和清空文件内容。 

1.2、以追加的方式打开文件

1、如果文件不存在,就在当前路径下新建指定的文件。
2、默认打开文件的时候,会在末尾追加内容 ->  等价于 >>输出重定向。

 代码演示

#include<stdio.h>int main()
{// 以追加的方式打开文件FILE* fd = fopen("log.txt","a");if(fd == NULL) {perror("fopen");return 1;}fprintf(fd,"helloworld,%d,%s,%lf\n",10,"abcd",3.14);fclose(fd);return 0;
}

运行结果 

看一段命令 

[jkl@host file]$ ./myfile
[jkl@host file]$ cat log.txt
helloworld,10,abcd,3.140000
helloworld,10,abcd,3.140000
helloworld,10,abcd,3.140000
[jkl@host file]$ cat myfile.c
[jkl@host file]$ echo "hello linux" >> log.txt
[jkl@host file]$ cat log.txt
helloworld,10,abcd,3.140000
helloworld,10,abcd,3.140000
helloworld,10,abcd,3.140000
hello linux
[jkl@host file]$ >> file1.txt
[jkl@host file]$ ls
file1.txt  file.txt  log.txt  makefile  myfile  myfile.c

解析命令 

结论: 

>> 追加重定向可以创建新文件和追加文件内容。 

2、初步理解文件

  • 文件 = 属性 + 内容
  • 打开文件:本质是进程(struct task_struct)打开文件(struct xxx)
  • 文件没有打开的时候,存放在哪里?硬盘。
  • 进程能打开很多文件吗?可以
  • 系统能否存在很多进程?可以
  • 很多情况下,OS内部存在大量被打开的文件 -> OS是否要将被打开的文件进行管理 -> 怎么管理呢?先描述在组织 -> 预言:每一个被打开的文件,在OS内部,一定要存在对应的描述文件属性的结构体,类似于PCB。

2.1、C++文件接口

以写的方式打开文件。

代码演示

#include<iostream>
#include<fstream>
#include<string>#define FILENAME "log.txt"int main()
{// out写方式 in读方式 app追加 binary二进制std::ofstream out(FILENAME,std::ios_base::out);// is_open() 检查文件是否打开if(!out.is_open()) return 1; //打开失败,结束程序std::string msg = "hello C++!\n";// ostream& write (const char* s, streamsize n);out.write(msg.c_str(),msg.size());// 关闭文件out.close();return 0;
}

运行结果 

3、进一步理解文件

操作文件:本质是进程在操作文件,即进程与文件的关系。

文件 ->存储在硬盘中 -> 硬盘是一个外设 -> 外设是一个硬件 -> 向文件中写入本质是向硬件中写入 -> 用户没有权利直接写入 -> OS是硬件的管理者 -> 通过OS写入 -> OS必须给我们提供系统调用(因为OS不相信任何人) -> fopen/fwrite/fread/fclose ... -> 我们用的都是C/C++/... 对系统调用接口的封装! -> 访问文件,我们也可以直接使用系统调用!!!

为什么要对系统调用的接口进行封装?怎么封装?

后序回答。

使用系统调用接口来操作文件!!!

系统调用接口函数

打开文件

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);pathname: 要打开或创建的目标文件。
flags:     打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。
mode:设置默认权限信息。
参数:O_RDONLY: 只读打开O_WRONLY: 只写打开O_RDWR  : 读,写打开这三个常量,必须指定一个且只能指定一个O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限O_APPEND: 追加写O_TRUNC : 若文件存在会先清空文件 
返回值:成功:新打开的文件描述符失败:-1

向文件中写内容 

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

将缓冲区指向的 buf 内容中的count个字节数写入到文件描述符 fd 引用的文件。 

关闭文件 

#include <unistd.h>
int close(int fd);

关闭文件描述符 fd 引用的文件。

3.1、系统调用实现写方式打开文件

系统调用可能用到的头文件

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

代码演示一(不设置权限信息)

int main()
{int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC);if(fd < 0){perror("open");return 1;}// ssize_t write(int fd, const void *buf, size_t count);const char* msg = "hello linux file!\n";write(fd,msg,strlen(msg));close(fd);return 0;
}

运行结果

上面的代码演示的是文件不存在,在当前路径创建指定文件,但没有设置默认权限的情况。 

代码演示一(只设置权限信息)

int main()
{int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);if(fd < 0){perror("open");return 1;}// ssize_t write(int fd, const void *buf, size_t count);const char* msg = "hello linux file!\n";write(fd,msg,strlen(msg));close(fd);return 0;
}

运行结果 

上面的代码演示的是文件不存在,在当前路径创建指定文件,且设置默认权限的情况。  

 想要第三个参数是什么权限文件就是什么权限应该怎么办呢???

将umask值设置为0即可。

#include <sys/types.h>
#include <sys/stat.h>mode_t umask(mode_t mask);

设置umask值。

代码演示三(设置权限信息和umask)

int main()
{umask(0);int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);if(fd < 0){perror("open");return 1;}// ssize_t write(int fd, const void *buf, size_t count);const char* msg = "hello linux file!\n";write(fd,msg,strlen(msg));close(fd);return 0;
}

运行结果 

上面的代码演示的是文件不存在,在当前路径创建指定文件,且设置默认权限和umask的情况。   

代码演示四

int main()
{umask(0);int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0777);if(fd < 0){perror("open");return 1;}close(fd);return 0;
}

 运行结果

上面的代码演示的是文件存在,先清空文件内容,即使修改默认权限,也不会影响该文件的权限。   

3.2、系统调用实现追加打开文件

代码演示

int main()
{umask(0);int fd = open("log.txt",O_WRONLY | O_CREAT | O_APPEND,0666);if(fd < 0){perror("open");return 1;}// ssize_t write(int fd, const void *buf, size_t count);const char* msg = "hello linux file!\n";write(fd,msg,strlen(msg));close(fd);return 0;
}

运行结果

 3.3、理解open第二个参数原理

原理是位图加位运算,下面通过一个程序理解调用open第二个参数原理。

代码演示 

#define ONE   1       // 0000 0001
#define TWO   (1<<1)  // 0000 0010
#define THREE (1<<2)  // 0000 0100
#define FOUR  (1<<3)  // 0000 1000void print(int flag)
{if(flag & ONE){printf("one\n");}if(flag & TWO){printf("two\n");}if(flag & THREE){printf("three\n");}if(flag & FOUR){printf("four\n");}
}
int main()
{print(ONE);printf("\n");print(TWO);printf("\n");print(ONE | TWO);printf("\n");print(ONE | TWO | THREE);printf("\n");print(ONE | TWO | THREE | FOUR);printf("\n");return 0;
}

运行结果 

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

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

相关文章

element-ui 通过按钮式触发日期选择器

element ui 写在前面1. 自定义的日期时间组件CustomDatePicker.vue2. 页面效果总结写在最后 写在前面 需求&#xff1a;elementui中日期时间选择器&#xff0c;目前只能通过点击input输入框触发日期选择器&#xff0c;我希望能通过其他方式触发日期选择器同时把input输入框去掉…

【经典机器学习算法】谱聚类算法及其实现(python)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;深度学习_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前言 2. 前…

模版and初识vector

一、引言 在C语言中&#xff0c;不论是数组&#xff0c;还是结构体定义的数组&#xff0c;功能都比较欠缺&#xff0c;不是单纯的添加几个变量就能够解决的。缺少增删查改的功能&#xff0c;为了解决这个问题&#xff0c;C决定填上C语言这个坑&#xff0c;但是填过坑的人都知道…

线性DP之最长上升/下降子序列

分析过程&#xff1a; 代码&#xff1a; #include<bits/stdc.h> #include<unordered_map> #include<unordered_set> using namespace std; #define int long long //可能会超时 #define PII pair<int,int> const int INF 0x3f3f3f3f, mod 99824435…

认知杂谈73《成年人的修炼:勇敢前行,积极向上》

内容摘要&#xff1a; 成长是成年人的必修课&#xff0c;它要求我们不断学习、面对挑战、做出选择、调整行动。成长的必要性在于适应社会、实现自我价值。实现成长的策略包括自我掌舵、自救、为结果负责、保持积极心态。 追求艺术或商业目标、自己解决问题、承担责任、换个角度…

Android 车载虚拟化底层技术-显示虚拟化(双card)总览

系列文章请扫关注公众号&#xff01; 本文主要包括部分&#xff1a; 显示虚拟化场景DRM架构 2.1 DRM简介&#xff08;Direct Rendering Manager&#xff09; 2.2 高通SDM驱动 Multiple-drm-cards方案 3.1 介绍 3.2 Qcom驱动框架解析 3.3 高通及MTK平台支持情况 3.4 方案…

针对考研的C语言学习(定制化快速掌握重点2)

1.C语言中字符与字符串的比较方法 在C语言中&#xff0c;单字符可以用进行比较也可以用 > , < ,但是字符串却不能用直接比较&#xff0c;需要用strcmp函数。 strcmp 函数的原型定义在 <string.h> 头文件中&#xff0c;其定义如下&#xff1a; int strcmp(const …

基于深度学习的乳腺癌分类识别与诊断系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 乳腺癌是全球最常见的癌症之一&#xff0c;早期诊断对于治疗效果至关重要。近年来&#xff0c;深度学习技术在医学图像分析领域取得了显著进展&#xff0c;能够从大量的医学影像数据中自动学习和提…

TiDB 在线打标签实现副本调度应用实践

作者&#xff1a; 数据源的TiDB学习之路 原文来源&#xff1a; https://tidb.net/blog/4e14596a 案例背景 某原有系统为虚拟机环境部署&#xff0c;整体性能不满足预期。为提升集群整体性能&#xff0c;计划分阶段采购物理机&#xff0c;并以扩缩容的方式逐渐把物理机添加到…

uniapp踩坑 tabbar页面数据刷新了但视图没有更新

问题描述&#xff1a; 有个uni-data-checkbox组件&#xff0c;两个选项&#xff1a;选项1和选项2&#xff08;对应的value值分别为1和2&#xff09;&#xff0c;v-model绑定属性名为value 两个tabbar页面&#xff1a;tab1&#xff0c;tab2。 tab1页面有个逻辑是在onShow中刷新v…

IDEA 设置自动定位文件

一、场景分析 IDEA 在使用的过程中&#xff0c;发现有时候&#xff0c;打开一个类&#xff0c;它并不能自动帮我们在左侧 Project 树中定位出文件&#xff0c;需要自己手动点击 瞄准 图标。很不方便。 二、解决方法 1、点击 瞄准 图标旁边的 竖三点 2、将 Alwasy Select Opene…

Kubernetes云原生存储解决方案之 Rook Ceph实践探究

Kubernetes云原生存储解决方案之 Rook Ceph实践探究 除了手动部署独立的 Ceph 集群并配置与Kubernetes进行对接外&#xff0c;Rook Ceph 支持直接在 Kubernetes 集群上部署 Ceph 集群。 通过Rook Ceph云原生存储编排平台&#xff0c;使得 Kubernetes 集群中启用高可用的 Ceph…

text2sql方法:NatSQL和DIN-SQL

NatSQL NatSQL出自2021年9月的论文《Natural SQL: Making SQL Easier to Infer from Natural Language Specifications》(github)&#xff0c;它是一种SQL 中间表征(SQL intermediate representation(IR))方法。 NatSQL作者认为Text2SQL的关键挑战是自然语言描述和其对应的SQ…

数据结构——“AVL树”的四种数据旋转的方法

因为上次普通的二叉搜索树在极端情况下极容易造成我们的链式结构&#xff08;这会导致我们查询的时间复杂度变为O(n)&#xff09;&#xff0c;然而AVL树就很好的解决了这一问题&#xff08;归功于四种旋转的方法&#xff09;&#xff0c;它让我们的树的查询的时间复杂度变得接近…

Dapper 如何确保数据的安全性和防止 SQL 注入攻击?

一、什么是SQL注入攻击 SQL注入攻击是一种常见的网络攻击手段&#xff0c;它利用了应用程序中安全措施不足的问题&#xff0c;允许攻击者插入或“注入”一个或多个SQL语句到原本的查询中。这种攻击可以用于获取、篡改或删除数据库中的数据&#xff0c;甚至可以执行一些数据库管…

【web安全】——sql注入

1.MySQL基础 1.1information_schema数据库详解 简介&#xff1a; 在mysql5版本以后&#xff0c;为了方便管理&#xff0c;默认定义了information_schema数据库&#xff0c;用来存储数据库元数据信息。schemata(数据库名)、tables(表名tableschema)、columns(列名或字段名)。…

字节豆包C++一面-面经总结

talk is cheap show me the code lc206&#xff1a;链表反转&#xff1a;给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 class Solution { public:ListNode* reverseList(ListNode* head) {if(headnullptr||!head->next)return head…

sentinel原理源码分析系列(二)-动态规则和transport

本文是sentinel原理源码分析系列第二篇&#xff0c;分析两个组件&#xff0c;动态配置和transport 动态规则 Sentinel提供动态规则机制&#xff0c;依赖配置中心&#xff0c;如nacos&#xff0c;zookeeper&#xff0c;组件支持动态配置&#xff0c;模板类型为规则&#xff0c;支…

Qt开发技巧(九)去掉切换按钮,直接传样式文件,字体设置,QImage超强,巧用Qt的全局对象,信号槽断连,低量数据就用sqlite

继续讲一些Qt开发中的技巧操作&#xff1a; 1.去掉切换按钮 QTabWidget选项卡有个自动生成按钮切换选项卡的机制&#xff0c;有时候不想看到这个烦人的切换按钮&#xff0c;可以设置usesScrollButtons为假&#xff0c;其实QTabWidget的usesScrollButtons属性最终是应用到QTabWi…

python调用opencv报错“module ‘cv2‘ has no attribute ‘namedWindow‘”

之前电脑上使用pip install安装过opencv相关的python模块&#xff0c;不过后续学习opencv时主要使用OpenCVSharp在VS2022中创建项目测试。今天学习过程中突然想用python试试&#xff0c;不过运行下面代码时报错“module ‘cv2’ has no attribute namedWindow”。 import cv2c…