Linux 文件:IO接口详解及实操

一、C语言中的文件IO读写操作

在c语言文件中,创建、打开、读、写操作可以通过如下的代码进行:

1.1写文件

通过'w'指令对文件进行写入操作时,编译器会先将文件内容清空然后重新写入。

#include <stdio.h>
#include <string.h>
int main()
{
     FILE *fp = fopen("myfile", "w");
     if(!fp){
     printf("fopen error!\n");
     }
     const char *msg = "hello bit!\n";
     int count = 5;
     while(count--){
     fwrite(msg, strlen(msg), 1, fp);
     }
     fclose(fp);
     return 0;
}

1.2读文件

#include <stdio.h>
#include <string.h>
int main()
{
 FILE *fp = fopen("myfile", "r");
 if(!fp){
 printf("fopen error!\n");
 }
 char buf[1024];
 const char *msg = "hello linux!\n";
while(1){
 //注意返回值和参数,此处有坑,仔细查看man手册关于该函数的说明
 ssize_t s = fread(buf, 1, strlen(msg), fp);
 if(s > 0){
 buf[s] = 0;
 printf("%s", buf);
 }
 if(feof(fp)){
 break;
 }
 }
 fclose(fp);
 return 0;
}

1.3输出文件

#include <stdio.h>
#include <string.h>
int main()
{
 const char *msg = "hello fwrite\n";
 fwrite(msg, strlen(msg), 1, stdout);
 printf("hello printf\n");
 fprintf(stdout, "hello fprintf\n");
 return 0;
}

1.4stdin & stdout & stderr

C默认会打开三个输入输出流,分别是stdin, stdout, stderr。
仔细观察发现,这三个流的类型都是FILE*, fopen返回值类型,文件指针。
 r Open text file for reading. 
 The stream is positioned at the beginning of the file.
 
 r+ Open for reading and writing.
 The stream is positioned at the beginning of the file.
 
 w Truncate(缩短) file to zero length or create text file for writing.
 The stream is positioned at the beginning of the file.
 
 w+ Open for reading and writing.
 The file is created if it does not exist, otherwise it is truncated.
 The stream is positioned at the beginning of the file.

a Open for appending (writing at end of file). 
 The file is created if it does not exist. 
 The stream is positioned at the end of the file

a+ Open for reading and appending (writing at end of file).
 The file is created if it does not exist. The initial file position
 for reading is at the beginning of the file, 
 but output is always appended to the end of the file

二、系统文件IO

操作文件,除了上述 C 接口(当然, C++ 也有接口,其他语言也有),我们还可以采用系统接口来进行文件访问,先来直接以代码的形式,实现和上面一模一样的代码:

2.1写文件

#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 linux!\n";
 int len = strlen(msg);
 while(count--){
 write(fd, msg, len);//fd:系统返回的文件描述符 , msg:缓冲区首地址, len: 本次读取,期望写入多少个字节的数
据。 返回值:实际写了多少字节数据
 }
 close(fd);
 return 0;
}

2.2读文件

#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 linux!\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;
}

2.3接口功能介绍

open:
open 函数具体使用哪个,和具体应用场景相关,如目标文件不存在,需要open创建,则第三个参数表示创建文件的默认权限,否则,使用两个参数的open。
#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。
参数:
 O_RDONLY: 只读打开
 O_WRONLY: 只写打开
 O_RDWR : 读,写打开
 这三个常量,必须指定一个且只能指定一个
 O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
 O_APPEND: 追加写
返回值:
 成功:新打开的文件描述符
 失败:-1
系统调用接口和库函数的关系,一目了然。
所以,可以认为, f# 系列的函数,都是对系统调用的封装,方便二次开发。

2.4文件描述符fd

Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2.
0,1,2对应的物理设备一般是:键盘,显示器,显示器
所以输入输出还可以采用如下方式
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main()
{
 char buf[1024];
 ssize_t s = read(0, buf, sizeof(buf));
 if(s > 0){
 buf[s] = 0;
 write(1, buf, strlen(buf));
 write(2, buf, strlen(buf));
 }
 return 0;
}

而现在知道,文件描述符就是从 0 开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file 结构体。表示一个已经打开的文件对象。而进程执行 open 系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files, 指向一张表 files_struct, 该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件。

三、文件描述符分配规则

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
 int fd = open("myfile", O_RDONLY);
 if(fd < 0){
 perror("open");
 return 1;
 }
 printf("fd: %d\n", fd);
 close(fd);
 return 0;
}//结果为fd:3
int main()
{
 close(0);
 //close(2);
 int fd = open("myfile", O_RDONLY);
 if(fd < 0){
 perror("open");
 return 1;
 }
 printf("fd: %d\n", fd);
 close(fd);
 return 0;
}//结果为0
文件描述符的分配规则:在 files_struct 数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。

四、重定向

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
 close(1);
 int fd = open("myfile", O_WRONLY|O_CREAT, 00644);
 if(fd < 0){
 perror("open");
 return 1;
 }
 printf("fd: %d\n", fd);
 fflush(stdout);
 
 close(fd);
 exit(0);
}
此时,我们发现,本来应该输出到显示器上的内容,输出到了文件 myfile 当中,其中, fd 1 。这种现象叫做输出重定向。当编译器去进行printf时会默认去打开fd=1的文件描述符所指向的,此时我们将myfile文件放到这个位置,那么编译器就会往myfile文件中进行写入。

五、使用dup2系统调用

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
 int fd = open("log.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
    dup2(fd, 1);
    printf("hello hahahaha\n");
 return 0;
}
在理解重定向之后,我们直接使用close这种操作来实现重定向就显的较为暴力且存在很多不稳定因素,使用dup2就可以很好的解决这个问题,将oldfd拷贝到newfd,通过这种方式,我们就可以将内容printf到log.txt中。

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

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

相关文章

前端上传大文件使用分片上传

前提:分片上传针对于一些大的文件、普通大小的文件使用element中的上传组件可以实现效果,例如几G的文件就会比较卡,所以这时候就需要用到分片上传~ 前端及后端分片上传笔记 效果:(上传进度展示) 效果:(上传成功的效果展示) 1、 新建一个上传组件 2、使用vue-simple-…

ATF(TF-A)安全通告TF-V11——恶意的SDEI SMC可能导致越界内存读取(CVE-2023-49100)

目录 一、ATF(TF-A)安全通告TFV-11 (CVE-2023-49100) 二、透过事务看本质SDEI是干啥的呢&#xff1f; 三、CVE-2023-49100 1、GICv2 systems 2、GICv3 systems 四、漏洞修复 一、ATF(TF-A)安全通告TFV-11 (CVE-2023-49100) Title 恶意的SDEI SMC可能导致越界内存读取&am…

java数据结构与算法刷题-----LeetCode667. 优美的排列 II

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 解题思路 题目要求我们返回一个数组长度为n的数组&#xff0c;必须含有1~n…

ZK高可用架构涉及常用功能整理

ZK高可用架构涉及常用功能整理 1. zk的高可用系统架构和相关组件1.1 Quorum机制1.2 ZAB协议 2. zk的核心参数2.1 常规配置2.2 特殊优化配置 3. zk常用命令3.1 常用基础命令3.2 常用运维命令 4. 事务性4.1 数据写流程4.2 数据读流程 5. 疑问和思考5.1 zk不擅长处理哪些场景&…

详解一次一密

目录 一. 介绍 二. 一次一密方案 三. 正确性分析 四. 证明一次一密方案是完美安全 五. 一次一密的应用 六. 小结 一. 介绍 一次一密&#xff0c;英语写做one time pad。 在1917年&#xff0c;Vernam提出了一个完美安全的加密方案&#xff0c;后世将其称之为一次一密。在…

Element中的el-input-number+SpringBoot+mysql

1、编写模板 <el-form ref"form" label-width"100px"><el-form-item label"商品id&#xff1a;"><el-input v-model"id" disabled></el-input></el-form-item><el-form-item label"商品名称&a…

选择国产压测工具应注意什么?

随着互联网和信息技术的飞速发展&#xff0c;压力测试成为了确保软件系统稳定性和性能的不可或缺的环节。在压测工具的选择上&#xff0c;近年来国产压测工具逐渐崭露头角&#xff0c;但在使用时仍需谨慎。本文将探讨在选择国产压测工具时需要注意的关键因素。 功能完备性&…

离线编译 onnxruntime-with-tensortRT

记录为centos7的4090开发机离线编译onnxruntime的过程&#xff0c;因为在离线的环境&#xff0c;所以踩了很多坑。 https://onnxruntime.ai/docs/execution-providers/TensorRT-ExecutionProvider.html 这里根据官网的推荐安装1.15 版本的onnx 因为离线环境&#xff0c;所以很…

中国大模型迎来“95后” 百度奖学金发掘百位“未来AI技术领袖”

在人工智能掀起的科技革命和产业变革浪潮下&#xff0c;大模型成为最受关注的研究领域。1月22日&#xff0c;第十一届百度奖学金颁奖典礼在北京举行&#xff0c;来自全球顶尖高校及科研机构的10位“未来AI技术领袖”脱颖而出&#xff0c;他们平均年龄仅27岁&#xff0c;其中8人…

关于Redis的最常见的十道面试题-分布式锁和布隆过滤器

面试题一&#xff1a;有序集合在日常工作中的使用场景有哪些&#xff1f; 有序集合在工作中的应用场景有很多&#xff0c;例如“ 排行榜&#xff1a;可以将用户的得分作为有序集合的分支&#xff0c;用户的ID作为成员&#xff0c;通过有序集合的排名功能可以得到用户的排名信…

OpenCV第 2 课 OpenCV 环境搭建

文章目录 第 2 课 OpenCV 环境搭建1.安装 Numpy2.从 Ubuntu 存储库安装 OpenCV3.验证 OpenCV 安装 第 2 课 OpenCV 环境搭建 1.安装 Numpy 每一张图像都有很多个像素点&#xff0c;这也导致了程序中会涉及大量的数组处理。Numpy 是一个 Python 的拓展库&#xff0c;它对多维数…

MySQL怎么根据当前时间获取连续十二个月统计数据

需求 在某些业务场景中&#xff0c;需要后台获取连续十二个月的统计数据&#xff0c;如下图&#xff1a; 解决方式 1、创建一张临时表&#xff0c;在表中插入序号数据 该表的最大数量决定统计返回的最大条数 CREATE TABLE sys_redundancy (id bigint(22) NOT NULL AUTO_I…

YOLOv7调用摄像头检测报错解决

yolov7detect.py文件调用本地摄像头&#xff0c;把source参数设为0 parser.add_argument(--source, typestr, default0, helpsource) # file/folder, 0 for webcam 报错&#xff1a;cv2.error: OpenCV(3.4.2) 一堆地址:The function is not implemented. Rebuild the library…

【数据分析】matplotlib、numpy、pandas速通

教程链接&#xff1a;【python教程】数据分析——numpy、pandas、matplotlib 资料&#xff1a;https://github.com/TheisTrue/DataAnalysis 1 matplotlib 官网链接&#xff1a;可查询各种图的使用及代码 对比常用统计图 1.1 折线图 &#xff08;1&#xff09;引入 from …

时间序列大模型:TimeGPT

论文&#xff1a;https://arxiv.org/pdf/2310.03589.pdf TimeGPT&#xff0c;这是第一个用于时间序列的基础模型&#xff0c;能够为训练期间未见过的多样化数据集生成准确的预测。 大规模时间序列模型通过利用当代深度学习进步的能力&#xff0c;使精确预测和减少不确定性成为…

力扣hot100 排序链表 归并排序 递归

Problem: 148. 排序链表 &#x1f469;‍&#x1f3eb; 参考 &#x1f496; 归并排序&#xff08;递归&#xff09; ⏰ 时间复杂度: O ( n ) O(n) O(n) &#x1f30e; 空间复杂度: O ( n ) O(n) O(n) /*** Definition for singly-linked list.* public class ListNode {*…

【Go学习】Ginkgo测试框架学习实践 + 问题记录 + 怎么解决(0)

1、ginkgo测试框架介绍&#xff1a;https://onsi.github.io/ginkgo/ 2、重点是学习实践 问题记录 怎么解决 3、送福利&#xff1a;国内好用的ChatGpt有很多&#xff0c;比如&#xff1a;天工、文心一言、讯飞星火、通义万相等 1. 安装 xxxmacdeMacBook-Pro-3  /Volumes/mac…

Linux驱动程序

驱动程序框架: dev_t dev_num; struct file_operations fops {.open //define function.read //define function.write //define function };struct cdev dev;demo_init() { MKDEV(); cdev_init(); cdev_add(); register_chrdev_region(); //class_create(); //device…

opendds之GUID理解

在opendds的调试日志中大量充斥各种entity的guid&#xff0c;如下所示&#xff1a; (838182|838209) DataLink::release_reservations() - releasing association local: 0103bab5.84e0eba6.ca269681.01000004(b02bd8da) <--> with remote 0103bab5.84e0eba6.a56d6aff.01…

自定义错误页面在Spring Boot中的实现

引言 在SpringBoot中&#xff0c;常用的异常处理有两种&#xff1a;一种是 BasicErrorController&#xff0c;另一种是 ControllerAdvice。BasicErrorController 用于处理非Controller抛出的异常&#xff0c;而ControllerAdvice 用于处理Controller抛出的异常&#xff0c;对于…