Standard IO

为了提高可移植性,将通用IO接口经过再封装就形成了标准IO,标准IO不仅适用于Unix环境,也兼容非Unix环境,这也是为什么说我们应该尽可能的使用标准IO,通用IO通过文件描述符fd来与文件交互,为了以示区分,标准IO定义了流的概念作为与文件交互的入口

文件流

文件流是一个FILE*类型的变量,FILE是C标准定义的一个结构体,内部维护了进程对于文件的各种信息,其中就包括了文件描述符,文件流对于标准IO非常重要,几乎所有的标准IO接口都需要使用到文件流,就如同几乎所有的通用IO需要用到文件描述符一样。

标准流

标准流是比较特殊的文件流,分别是标准输出、标准输入和标准错误,这三个文件流在程序启动时就会默认打开,这也是为什么我们在包含头文件之后可以直接进行scanf和printf的原因(回想一下,你使用scanf和printf时几乎不需要接触流这个概念吧)

标准中分别用stdin、stdout、stderr三个宏常量来表示标准流

缓冲区

标准IO相比于通用IO最显著的特点就是缓冲区,这里的缓冲区是用户缓冲区,缓冲机制使得标准IO真实读写磁盘的次数大大减少从而大大提高了效率

缓冲区策略

  • 页缓冲:缓冲区中的数据超过一页大小(4096bytes)时进行一次落盘
  • 行缓冲:遇到换行符进行一次落盘(超过一页也会落盘)
  • 不缓冲:有数据就落盘

默认情况下 磁盘文件采用页缓冲;标准输入输出文件采用行缓冲;标准错误文件不缓冲

可以通过setbuf和setvbuf显式设置对应文件流的缓冲策略

void setbuf(FILE* fp,char* buf);
int setvbuf(FILE* fp,char* buf,int mode,size_t size); //return no-zero if error

setbuf可以决定是否采用缓冲策略

​ buf为空时不缓冲,否则采用行缓冲或页缓冲(根据文件特点),buf若非空长度必须指向长度为BUFSIZE的缓冲区(C标准提供的常量)

setvbuf可以更精确设置缓冲策略

通过buf和size的配合,可以灵活的设置大小为size的缓冲区,mode的取值决定缓冲策略(如果buf为空将由系统自动分配用户缓冲区)

mode取值

  • _IOFBF 页缓冲
  • _IOLBF 行缓冲
  • _IONBF 不缓冲

强制刷盘

int fllush(FILE* fp);
//return no-zero if error

调用fllush可以暂时无视缓冲区策略,直接对缓冲区中的数据进行刷盘操作

文件流操作

打开流

FILE* fopen(const char* pathname,const char* type);
FILE* freopen(const char* pathname,const char* type,FILE* fp);
FILE* fdopen(int fd,const char* type);
//return NULL if error

freopen可以复用FILE*变量,在一个已经打开的文件流上再次打开一个文件流,原先打开的文件流会先关闭

由于fopen一般只用于打开普通文件,对于一些只能用open打开的文件可以先获取其文件描述符,再通过fdopen将文件描述符与一个流结合,后续以同一的文件流进行读写

打开模式

在这里插入图片描述

b表示二进制模式打开

关闭流

int fclose(FILE* fp);
//return no-zero if error

读写流

字符读写

int getc(FILE* fp);
int fgetc(FILE* fp);
int getchar();
//return ASCII if succeed,or EOF(-1)

int putc(int c,FILE* fp);
int fputc(int c,DILE* fp);
int putchar(int c);
//return ASCII if succeed,or EOF

getc和fgetc等价

getchar用于从标准输入流读取

putc和fputc等价

putchar用于打印至标准输出流

行读写

char* fgets(char* buf,int n,FILE* fp);
//return buf if succeed,or NULL

int fputs(const char* str,FILE* fp);
int puts(const char* str);
//return no-zero if succeed ,or NULL

对于 fgets,必须指定缓冲的长度n。它一直读到下一个换行符为止,但是不超过 n-1个字符,读入的字符被送入缓冲区。该缓冲区以**\0结尾**。如若该行包括最后一个换行符的字符数超过 n-1,则 fgets 只返回一个不完整的行,但是,缓冲区总是以 -\0结尾。对 fgets的下一次调用会继续读该行

eg:

#include <stdio.h>

int main()
{
    char buf[4]={0};
    while(1){
        fgets(buf,4,stdin);
        puts(buf); //这里使用puts的自动换行功能可以更明显看出fgets对于一次输入分2次完成
    }
    return 0;
}
多用fputs而非puts

puts直接在标准输出上显示内容,它会自动添加换行符,但是C语言中大多数输出没有这种特性,fputs不会自动添加换行符,更有C风格

结束与错误

int ferror(FILE* fp);
int feof(FILE* fp);

void clearerr(FILE* fp);

如果文件出错ferror返回非0值;如果文件读完则feof返回非0值

FILE结构中维护了出错标志和结束标志,当我们使用ferror或feof判断返回EOF的原因并进行问题处理后,一般希望将这2位归置,可以通过clearerr(FILE fp)*方法

二进制读写

size_t fread(void* ptr,size_t size,size_t n,FILE* fp);
size_t fwrite(const void* ptr,size_t size,size_t n,FILE* fp);
//返回实际读写的个数(单位为size)

非二进制读写都规定了\0作为结束符,二进制读写则没有规定结束符,它严格地按照指定读取个数(n)来读取数据,n的单位不是字节,而是第二个参数size

eg1:fwrite和fputs

int main()
{
    char buf[BUFSIZ]="123\0 456";
    fputs((const char*)buf,stdout); //只会打印123
    puts("");
    fwrite((const void*)buf,1,10,stdout); //打印123\0 456
    return 0;
}

eg2:二进制读写结构

typedef struct student{
    int id;
    char name[16];
}student;
int main()
{
    student s[3]={{1,"zhangsan "},{2,"lisi "},{3,"wangwu "}};
    fwrite((const void*)s,sizeof(student),3,stdout);
    return 0;
}

定位流

long ftell(FILE* fp);
int fseek(FILE* fp,long offset,int whence);
void rewind(FILE* fp);//回到起始位置

格式读写

int printf(const char* format,...);
int fprintf(FILE* fp,const char* format,...);
int snprintf(char* buf,size_t n,const char* format,...);//格式化字符串
//返回输出字符数,出错则为负值
int scanf(const char* format,...);
int fscanf(FILE* fp,const char* format,...);
int sscanf(const char* buf,const char* format,...);
//返回输入字符数,出错则为负值

格式化写占位符

在这里插入图片描述

格式化读占位符

在这里插入图片描述

内存流

所谓内存流就是不在磁盘上开辟空间,而是在内存上开辟空间存放数据,这些数据都是临时性的,因为内存没有持久化的功能,fmemopen使得用户可以像读写文件一样读写内存

FILE* fmemopen(void* buf,size_t size,const char* type);

内存流的打开模式稍显特殊。

  • 以追加写方式打开内存流时,当前文件位置设为缓冲区中的第一个\0字节。如果缓冲区中不存在\0字节,则当前位置就设为缓冲区结尾的后一个字节。因此内存流并不适合存储二进制数据(二进制数据在数据尾端之前就可能包含多个 null 字节)。

  • 如果buf参数是空指针,打开流进行读或者写都没有任何意义。因为在这种情况下缓冲区是通过 fmemopen进行分配的,没有办法找到缓冲区的地址,只写方式打开流意味着无法读取已写入的数据,同样,以读方式打开流意味着只能读取那些我们无法写入的缓冲区中的数据。

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

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

相关文章

极氪MIX:一台只有你想不到,没有它做不到的“家用神车”

了解极氪品牌的朋友应该都知道 极氪一直都在尝试打破目前汽车或者生活的一些现状 更愿意创造一些破界、超前的产品 比如说将家庭城市通勤、假日露营、自驾旅行、户外垂钓、朋友相聚等多场景融入一个空间的极氪MIX 这款车突破了SUV或MPV车型形态的固有限制 前悬仅 865mm&am…

【ArcGIS Pro实操第八期】绘制WRF三层嵌套区域

【ArcGIS Pro实操第八期】绘制WRF三层嵌套区域 数据准备ArcGIS Pro绘制WRF三层嵌套区域Map-绘制三层嵌套区域更改ArcMap地图的默认显示方向指定数据框范围 Map绘制研究区Layout-布局出图 参考 本博客基于ArcGIS Pro绘制WRF三层嵌套区域&#xff0c;具体实现图形参考下图&#x…

Centos安装Nginx 非Docker

客户的机器属于 Centos7 系列&#xff0c;由于其较为陈旧&#xff0c;2024开始众多镜像和软件源都已失效。此篇文章将详细记录在 Centos7 操作系统上从零开始安装 Nginx 的整个流程。 本文Nginx是安装在/usr/local/nginx下 详细步骤如下&#xff1a; 准备Nginx安装包&#x…

安防监控摄像头图传模组,1公里WiFi无线传输方案,监控新科技

在数字化浪潮汹涌的今天&#xff0c;安防监控领域也迎来了技术革新的春风。今天&#xff0c;我们就来聊聊这一领域的产品——摄像头图传模组&#xff0c;以及它如何借助飞睿智能1公里WiFi无线传输技术&#xff0c;为安防监控带来未有的便利与高效。 一、安防监控的新篇章 随着…

程序员适合玩的游戏:《人力资源机器》提升编程思维【Human Resource Machine】

程序员适合玩的游戏&#xff1a;《人力资源机器》提升编程思维【Human Resource Machine】 在当今这个技术日新月异的时代&#xff0c;编程已经成为一门不可或缺的技能。对于程序员来说&#xff0c;不仅需要扎实的专业知识&#xff0c;还需要不断锻炼逻辑思维和解决问题的能力…

用.NET开发跨平台应用程序采用 Avalonia 与MAUI如何选择

Avalonia是一个强大的框架&#xff0c;使开发人员能够使用.NET创建跨平台应用程序。它使用自己的渲染引擎绘制UI控件&#xff0c;确保在Windows、macOS、Linux、Android、iOS和WebAssembly等不同平台上具有一致的外观和行为。这意味着开发人员可以共享他们的UI代码&#xff0c;…

RNN、LSTM 与 Bi-LSTM

一. RNN 循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;是深度学习领域一类具有内部自连接的神经网络能够学习复杂的矢量到矢量的映射。 最大特点&#xff1a;前面的序列数据可以用作后面的结果预测中。 一个简单的循环神经网络结构&#xff0c;其结构包…

如何写一个视频编码器演示篇

先前写过《视频编码原理简介》&#xff0c;有朋友问光代码和文字不太真切&#xff0c;能否补充几张图片&#xff0c;今天我们演示一下&#xff1a; 这是第一帧画面&#xff1a;P1&#xff08;我们的参考帧&#xff09; 这是第二帧画面&#xff1a;P2&#xff08;需要编码的帧&…

Golang | Leetcode Golang题解之第480题滑动窗口中位数

题目&#xff1a; 题解&#xff1a; type hp struct {sort.IntSlicesize int } func (h *hp) Push(v interface{}) { h.IntSlice append(h.IntSlice, v.(int)) } func (h *hp) Pop() interface{} { a : h.IntSlice; v : a[len(a)-1]; h.IntSlice a[:len(a)-1]; return v }…

SCCB协议与IIC协议不同

SCCB开始信号与结束信号都与IIC协议的大概一致&#xff0c;这里就不细讲了 开始、结束信号参考&#xff1a;【I2C】IIC读写时序_iic读时序-CSDN博客 SSCB写时序&#xff1a; 即&#xff1a;start phase_1 phase_2 phase_3 stop SCCB读时序&#xff1a; 即&#xff…

电脑视频剪辑大比拼,谁更胜一筹?

随着短视频的火爆&#xff0c;越来越多的人开始尝试自己动手制作视频&#xff0c;无论是记录生活点滴还是创作个性短片&#xff0c;一款好用的视频剪辑软件是必不可少的。今天&#xff0c;我们就从短视频运营的角度&#xff0c;来聊聊几款热门的电脑视频剪辑软件&#xff0c;看…

在做题中学习(66):两数相加

解法&#xff1a;模拟 思路&#xff1a;定义一个变量t&#xff0c;存储相加后的结果&#xff0c;个位赋给新节点&#xff0c;十位&#xff08;表示有进位&#xff09;留下&#xff0c;累加到下一次加法&#xff08;相当于上进位&#xff09;。while里即便cur1和cur2都为空了&a…

windows文件拷贝给wsl2的Ubuntu

参考&#xff1a; windows文件如何直接拖拽到wsl中_win 移到文件到wsl-CSDN博客 cp -r /mnt/盘名/目标文件 要复制到wsl中的位置e.g.cp -r /mnt/d/byt5 /home Linux文件复制、移动、删除等操作命令_linux移动命令-CSDN博客 Linux 文件、文件夹的复制、移动、删除 - Be-myse…

重生之“我打数据结构,真的假的?”--1.顺序表(无习题)

C语言中的顺序表详细总结 1. 概述 顺序表&#xff08;Sequential List&#xff09;是一种线性数据结构&#xff0c;用于存储具有相同数据类型的一组元素。顺序表采用一段连续的存储空间&#xff0c;使用数组来实现&#xff0c;能够高效地支持随机访问操作。在 C 语言中&#…

No.19 笔记 | WEB安全 - 任意文件操作详解 part 1

1. 任意文件上传漏洞基础 什么是文件上传功能? 在网站和应用中,我们经常会看到允许用户上传文件的功能,比如: 更换头像:让用户上传自己的照片作为头像发布图片:在社交媒体或论坛上传图片提交文档:在办公系统中上传Word、Excel等文档 这些都是常见的文件上传功能。 任意文…

RabbitMQ系列学习笔记(四)--消息应答机制

文章目录 一、消息应答详解1、基本概念2、自动应答3、手动应答4、自动重新入队5、手动应答代码6、手动应答演示 二、不公平分发三、预取值机制 本文参考&#xff1a; 尚硅谷RabbitMQ教程丨快速掌握MQ消息中间件rabbitmq RabbitMQ 详解 Centos7环境安装Erlang、RabbitMQ详细过程…

如何去掉歌曲的人声只剩伴奏?伴奏独享的方法

在音乐制作、后期处理或是个人娱乐中&#xff0c;我们经常遇到需要将歌曲中的人声去除&#xff0c;仅保留伴奏的情况。虽然这一过程可能听起来颇为复杂&#xff0c;但实际上&#xff0c;借助现代音乐技术和软件&#xff0c;我们可以较为轻松地达成这一目标。本文将介绍三种常见…

[AWS]RDS数据库版本升级

背景&#xff1a;由于AWS上mysql5.7版本不再支持&#xff0c;需要进行版本升级。 吐槽&#xff1a;每年都要来那么几次&#xff0c;真的有病一样&#xff0c;很烦。 步骤一、升级检查 AWS提供了一个python的升级检测脚本&#xff0c;可以按照一下脚本下载测试&#xff1a; [r…

机器视觉基础系列2—简单了解用神经网络进行深度估计

机器视觉基础系列2—简单了解深度估计 深度估计 深度估计通俗的来讲就是要得到一张图像当中&#xff0c;哪些区域离得比较近&#xff0c;哪些区域离得比较远。 输入一张彩色得图像&#xff0c;我们输出深度估计得图像&#xff0c;深浅即为远近&#xff08;从而完成了离相机距离…

Git安装与配置(2.47.0版本超详细)

一、背景 1.什么是gitt&#xff1f;&#xff08;官网引用&#xff09; Git 是一个快速、可扩展的分布式版本控制系统&#xff0c;它拥有异常丰富的命令集&#xff0c;可以提供高级操作和对内部的完全访问。 参阅 gittutorial[7] 开始使用&#xff0c;然后查看 giteveryday[7] …