当前位置: 首页 > news >正文

Linux笔记 --- 标准IO

        系统IO的最大特点一个是更具通用性,不管是普通文件、管道文件、设备节点文件、接字文件等等都可以使用,另一个是他的简约性,对文件内数据的读写在任何情况下都是带任何格式的,而且数据的读写也都没有经过任何缓冲处理,这样做的理由是尽量精简内API,而更加丰富的功能应该交给第三方库去进一步完善。

        标准C库是最常用的第三方库,而标准IO就是标准C库中的一部分接口,这一部分口实际上是系统IO的封装,他提供了更加丰富的读写方式,比如可以按格式读写、按SCII码字符读写、按二进制读写、按行读写、按数据块读写等等,还可以提供数据读写冲功能,极大提高程序读写效率。

        所有的系统IO函数都是围绕所谓的“文件描述符”进行的,这个文件描符由函数open()获取,而所有的标准IO都是围绕所谓的“文件指针”进的,这个文件指针则是由fopen()获取的,他是第一个需要掌握的标准IO函数:

        打开/关闭

返回值的文件指针是一种指向FILE{}的结构体,在标准IO中被定义

 

可以看到,使用标准IO函数处理文件的最大特点是,数据将会先存储在一个标准IO缓冲区中,而后在一定条件下才被一并flush(冲洗,或称刷新)至内核缓冲区,而不是像系统IO那样,数据直接被 flush至内核。

注意到,标准IO函数 fopen()实质上是系统IO函数 open()的封装,他们是一一对应的,每一次fopen()都会导致系统分配一个file{}结构体和一个FILE{}来保存维护该文件的读写信息,每一次的打开和操作都可以不一样,是相对独立的,因此可以在多线程或者多进程中多次打开同一个文件,再利用文件空洞技术进行多点读写。

另外由上一节得知,标准输入输出设备是默认被打开的,在标准IO中也是一样,他们在程序的一开始就已经拥有相应的文件指针了:

跟fopen()配合使用的是fclose函数

 读写

标准IO的读写函数接非常多,下面列出最常用的函数集合

第一组:读写一个字符的函数        

需要注意的几点:

1,fgec()、getc()和getchar()返回值是int,而不是char,原因是因为他们在出 错或者读到文件末尾的时候需要返回一个值为—1的EOF标记,而char型数据有可能因为系统的差异而无法表示负整数。

2,当fgec()、getc()和getchar()返回EOF时,有可能是发生了错误,也有可能是读到了文件末尾,这是要用以下两个函数接口来进一步加以判断:

3,getchar()缺省从标准输入设备读取一个字符。

4,putchar()缺省从标准输出设备输出一个字符。

5,fgetc()和fputc()是函数,getc()和putc()是宏定义。

6,两组输入输出函数一般成对地使用,fgetc()和fputc(),getc()和putc(), getchar()和 putchar().

一个例子将这些函数的使用方法综合:

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>int main(int argc, char const *argv[])
{FILE *fp1 = fopen("in.txt","w");FILE *fp2 = fopen("out.txt","r");if(fp1 == NULL || fp2 == NULL){perror("fopen()");exit(1);}int c,total = 0;while (1){c = fgetc(fp2);if(c == EOF && feof(fp2)){printf("copy compeleted,%d was been copied\n",total);break;}else if(ferror(fp2)){perror("fgetc()");break;}fputc(c,fp1);total++;}fclose(fp1);fclose(fp2);return 0;
}

 

第二组:每次一行的读写函数 

值得注意的有以下几点:

1,fgets()跟fgetc()一样,当其返回NULL时并不能确定究竟是达到文件末尾还是碰到错误,需要用 feof()/ferror()来进一步判断。

2,fgets()每次读取至多不超过size个字节的一行,所谓“一行”即数据至多包含一个换行符\n′。

3,gets()是一个已经过时的接口,因为他没有指定自定义缓冲区s的大小,这样很容易造成缓冲区溢出,导致程序段访问错误。

4,fgets()和fputs(),gets()和puts()一般成对使用,鉴于gets()的不安全性, 一般建议使用前者。

下面是使用该组函数实现的普通文件拷贝示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>struct node //栈节点结构体
{int data;struct node *next;
};struct linked_stack //管理结构体
{int size;struct node *top;   //指向栈顶节点
};struct linked_stack *init_stack (void)
{struct linked_stack *s;s = malloc(sizeof(struct linked_stack));if(s != NULL){s->size = 0;s->top = NULL;}return s;
}//创建新节点
struct node *new_node(int data)
{struct node *new;new = malloc(sizeof(struct node));if(new != NULL){new->data = data;new->next = NULL;}return new;
}//压栈
bool push(struct linked_stack *s,struct node *new)
{if (s == NULL || new == NULL)return false;new->next = s->top;s->top = new;s->size++;return true;
}bool stack_empty(struct linked_stack *s)
{return s->size == 0;
}bool pop(struct linked_stack *s,struct node **p)
{if(s == NULL || p == NULL || stack_empty(s))return false;*p = s->top;s->top = s->top->next;(*p)->next = NULL;s->size--;return true;
}void show(struct linked_stack *A,struct linked_stack *B,struct linked_stack *C)
{FILE *fp; /*建立文件指针*/fp = fopen("/mnt/e/GZ2112/程序入门/test_txt/hano.txt","a");int maxlen,len;maxlen = A->size > B->size ? A->size : B->size;maxlen = maxlen > C->size ? maxlen : C->size;len = maxlen;struct node *t1 = A->top;struct node *t2 = B->top;struct node *t3 = C->top;int i;for (i = 0; i < maxlen; i++){if(t1 != NULL && len <= A->size){fprintf(fp,"%d",t1->data);t1 = t1->next;}fprintf(fp,"\t");if(t2 != NULL && len <= B->size){fprintf(fp,"%d",t2->data);t2 = t2->next;}fprintf(fp,"\t");if(t3 != NULL && len <= C->size){fprintf(fp,"%d",t3->data);t3 = t3->next;}fprintf(fp,"\t");fprintf(fp,"\n");len--;}fprintf(fp,"A\tB\tC\n");fprintf(fp,"-----------------\n");fclose(fp);
}void hano(struct linked_stack *A,struct linked_stack *B,struct linked_stack *C,int n)
{if(n <= 0)return;struct node *tmp;hano(A,C,B,n-1);    //将n-1块从A借助C移向Bgetchar();          //每回车一次进行一步show(A,B,C);pop(A,&tmp);push(C,tmp);        //将A最下面一块移动到Chano(B,A,C,n-1);    //将n-1块从B借助A移向C
}int main(int argc, char const *argv[])
{struct linked_stack *A = init_stack();struct linked_stack *B = init_stack();struct linked_stack *C = init_stack();int hanois = 0;scanf("%d",&hanois);int i;for (i = 0; i < hanois; i++){struct node *new = new_node(hanois-i);  //将汉诺塔中的块放入栈A(柱A)push(A,new);}hano(A,B,C,hanois);show(A,B,C);return 0;
}

第三组:每次读写若干数据块的标准IO接口函数

这一组标准IO函数被称为“直接IO函数”或者“二进制IO函数”,因为他们对数据的读写严格按照规定的数据块数和数据块的大小来处理,而不会对数据格式做任何处理,而且当数据块中出现特殊字符,比如换行符”\n、字符串结束标记”\0等时不会受到影响。需要注意的几点:

1,如果fread()返回值小于nmemb时,则可能已达末尾,或者遇到错误,需要借助于feof()/ferror()来加以进一步判断。

2,当发生上述第1种情况时,其返回值并不能真正反映其读取或者写入的数据块数,而只是一个所谓的“截短值”,比如正常读取5个数据块,每个数据块100个字节,在执行成功的情况下返回值是5,表示读到5个数据块总共500个字节,但是如果只读到499个数据块,那么返回值就变成4,而如果读到99个字节,那么fread()会返回0。因此当发生返回值小于nmemb时,需要仔细确定究竟读取了几个字节,而不能直接从返回值确定。

第四组:获取或设置文件当前位置偏移量

 

注意:

        1.fseek函数的使用基本与lseek函数相同
        2.rewind(fp)相当于fseek(fp,0L,SEEK_SET);

利用上面两组函数再次实现读写功能:

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>#define BUFSIZE 100
#define NMEMB 5int main(int argc, char const *argv[])
{FILE *fp1 = fopen("in.txt","w");FILE *fp2 = fopen("out.txt","r");if(fp1 == NULL || fp2 == NULL){perror("fopen()");exit(1);}char buf[BUFSIZE];int total = 0;long pos1 , pos2;while (1){bzero(buf,BUFSIZE);pos1 = ftell(fp2);if (fread(buf,BUFSIZE,NMEMB,fp2) < NMEMB){if(feof(fp2)){//将未满NMENB的数据写入pos2 = ftell(fp2);fwrite(buf,pos2 - pos1,1,fp1);total += pos2-pos1; printf("copy compeleted,%d was been copied\n",total);break;}else if(ferror(fp2)){perror("fgetc()");break;}}fwrite(buf,BUFSIZE,NMEMB,fp1);total += BUFSIZE * NMEMB;}fclose(fp1);fclose(fp2);return 0;
}

第五组:标准格式化IO函数

格式化IO函数中最常用的莫过于printf()和scanf()了,但从上表中可以看到,他们其实各自都有一些功能类似的兄弟函数可用,使用这些函数需要注意以下几点:
        1,fprintf()不仅可以像printf()一样向标准输出设备输出信息,也可以向由stream指定的任何有相应权限的文件写入数据。
        2,sprintf()和snprintf()都是向一块自定义缓冲区写入数据,不同的是后者第二个参数提供了这块缓冲区的大小,避免缓冲区溢出,因此应尽量使用后者,放弃使用前者。
        3,fscanf()不仅可以像scanf()一样从标准输入设备读入信息,也可以从由stream指定的任何有相应权限的文件读入数据。
        4,sscanf()从一块由s指定的自定义缓冲区中读入数据。
        5,最重要的一条:这些函数的读写都是带格式的,这些所谓的格式由下表规定:

 这一组函数与之前最大的区别在于带有格式控制,因此适用于有格式的文件处理,比如学生信息等等此类数据。

相关文章:

Linux笔记 --- 标准IO

系统IO的最大特点一个是更具通用性&#xff0c;不管是普通文件、管道文件、设备节点文件、接字文件等等都可以使用&#xff0c;另一个是他的简约性&#xff0c;对文件内数据的读写在任何情况下都是带任何格式的&#xff0c;而且数据的读写也都没有经过任何缓冲处理&#xff0c;…...

洛谷:B3625 迷宫寻路

迷宫寻路 题目描述 机器猫被困在一个矩形迷宫里。 迷宫可以视为一个 n m n\times m nm 矩阵&#xff0c;每个位置要么是空地&#xff0c;要么是墙。机器猫只能从一个空地走到其上、下、左、右的空地。 机器猫初始时位于 ( 1 , 1 ) (1, 1) (1,1) 的位置&#xff0c;问能否…...

【C#】explicit、implicit与operator

字面解释 explicit&#xff1a;清楚明白的;易于理解的;(说话)清晰的&#xff0c;明确的;直言的;坦率的;直截了当的;不隐晦的;不含糊的。 implicit&#xff1a;含蓄的;不直接言明的;成为一部分的;内含的;完全的;无疑问的。 operator&#xff1a;操作人员;技工;电话员;接线员;…...

Vue:Vuex-Store使用指南

一、简介 1.1Vuex 是什么 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension (opens new window)&#xf…...

对经典动态规划问题【爬台阶】的一些思考

背景 今天在做Leetcode题目时&#xff0c;做到了一道经典的动态规划问题&#xff1a;爬楼梯&#xff0c;题目的大致意思很简单&#xff0c;有个小孩正在上楼梯&#xff0c;楼梯有n阶台阶&#xff0c;小孩一次可以上1阶、2阶或3阶。实现一种方法&#xff0c;计算小孩有多少种上…...

开发一个能打造虚拟带货直播间的工具!

在当今数字化时代&#xff0c;直播带货已成为电商领域的一股强劲力量&#xff0c;其直观、互动性强的特点极大地提升了消费者的购物体验。 然而&#xff0c;随着技术的不断进步&#xff0c;传统直播带货模式正逐步向更加智能化、虚拟化的方向演进&#xff0c;本文将深入探讨如…...

汽车补光照明实验太阳光模拟器光源

汽车补光照明实验概览 汽车补光照明实验是汽车照明领域的一个重要环节&#xff0c;它涉及到汽车照明系统的性能测试和优化。实验的目的在于确保汽车在各种光照条件下都能提供良好的照明效果&#xff0c;以提高行车安全。实验内容通常包括但不限于灯光的亮度、色温、均匀性、响应…...

MediaPipe人体姿态、手指关键点检测

MediaPipe人体姿态、手指关键点检测 文章目录 MediaPipe人体姿态、手指关键点检测前言一、手指关键点检测二、姿态检测三、3D物体案例检测案例 前言 Mediapipe是google的一个开源项目&#xff0c;用于构建机器学习管道。   提供了16个预训练模型的案例&#xff1a;人脸检测、…...

树上dp之换根dp

基本概念&#xff1a; 换根dp是树上dp的一种 我们在什么时候需要用到换根dp呢&#xff1f; 当题目询问的属性&#xff0c;是需要当前结点为根时的属性&#xff0c;这个时候&#xff0c;我们就要使用换根dp 换根dp的基本思路&#xff1a; 假设题目询问的的属性为x 通常我们…...

2024/8/13 英语每日一段

Mackey says while Whole Foods has become more homogenized under Amazon, it did enable the store to do what it couldn’t have done independently. “People saw us as too expensive and out of touch with our customers,” he says. “The main thing Whole Foods n…...

Java多线程练习(1)

MultiProcessingExercise package MultiProcessingExercise120240813;public class MultiProcessingExercise {public static void main(String[] args) {/*需求&#xff1a;一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为3000毫秒,请用多线程模拟卖票过程并打印…...

AI高级肖像动画神器LivePortrait

文章目录 前言一、安装1.1 源码安装1.2 windows一键启动包 二、人像生成2.1 浏览器2.2 输入图像2.3 选择驱动视频2.4 生成2.5 结果 三、动物生成3.1 浏览器3.2 输入图片3.3 选择视频3.4 生成3.5 最终结果 四、软件获取 前言 最近&#xff0c;快手可灵大模型团队、中国科学技术…...

Java反射机制深度解析与实践应用

Java反射机制深度解析与实践应用 引言 Java反射是Java语言提供的一种能力&#xff0c;允许程序在运行时访问、检测和修改其自身的属性和行为。反射机制是Java面向对象编程的一大亮点&#xff0c;也是Java框架和库常用的技术之一。 反射的基本概念 反射的核心是java.lang.re…...

Oracle递归查询层级及路径

一、建表及插入数据 ocation_idlocation_nameparent_location_id1广东省NULL2广州市13深圳市14天河区25番禺区26南山区37宝安区3 建表sql&#xff1a; CREATE TABLE locations (location_id NUMBER PRIMARY KEY,location_name VARCHAR2(100),parent_location_id NUMBER ); I…...

leetcode300. 最长递增子序列,动态规划附状态转移方程

leetcode300. 最长递增子序列 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,2…...

C语言:字符串函数strcpy

该函数用于字符串的拷贝。 使用方法如下&#xff1a; #include<stdio.h> #include<string.h>int main() {char str[10];char* str1 "abcd";//strcpy(str, str1);//把str1复制到str&#xff0c;但此函数不安全所以用strcpy_sstrcpy_s(str, 10, str1);/…...

Day16-指针2

数组指针与指针数组 变量指针&#xff1a;指向变量的地址。 数组指针&#xff1a;指向数组的地址。 指针变量&#xff1a;存放其他变量地址的变量。 指针数组&#xff1a;存放数组元素指针的变量。 数组指针 概念&#xff1a;数组指针是指向数组的指针。特点&#xff1a; 先…...

数据结构(5.5_3)——并查集的进一步优化

Find操作的优化(压缩路径) 压缩路径——Find操作&#xff0c;先找到根节点&#xff0c;再将查找路径上所有结点都挂到根结点下 代码&#xff1a; //Find "查"操作优化&#xff0c;先找到根节点&#xff0c;再进行"路径压缩" int Find(int S[], int x) {…...

(回溯) LeetCode 131. 分割回文串

原题链接 一. 题目描述 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是 回文串。返回 s 所有可能的分割方案。 示例 1&#xff1a; 输入&#xff1a;s "aab" 输出&#xff1a;[["a","a","b"],[…...

【Linux】阻塞信号|信号原理|深入理解捕获信号|内核态|用户态|sigaction|可重入函数|volatile|SIGCHILD|万字详解

目录 ​编辑 一&#xff0c;常见的信号术语 二&#xff0c;信号在内核中的表示 信号标志位 Pending表 Block表 handler表 POSIX.1标准 三&#xff0c;sigset_t 信号集操作函数 sigemptyset sigfillset sigaddset sigdelset sigismember sigprocmask sig…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...