C专题8:文件操作1

1.C语言中的文件是什么?

        所谓文件(file)一般指存储在外部介质上数据的集合,比如我们经常使用的txt、bmp、jpg、exe、rmvb等等。这些文件各有各的用途,我们通常将它们存放在磁盘或者可移动盘等介质中。
文件无非就是一段数据的集合,这些数据可以是有规则的集合,也可以是无序的集合。操作系统也就是以文件为单位对数据进行管理的。也就是说,要访问外部介质上的数据,必须先按照文件名进行查找,然后从该文件中读取数据。要想写数据到外部介质,必须得建立一个文件,然后再写入。因此,你眼前的文件只是数据的集合。

1.1文件一般包括三要素:

        文件路径、文件名、后缀。
由于在C语言中''一般是转义字符的起始标志,故在路径中需要用两个''表示路径中目录层次的间隔,也可以使用'/'作为路径中的分隔符。
例如:
"D:\\123\\test.c"或者"D:/123/test.c",表示文件test.c保存在D盘123目录下。
"tu.txt"表示当前目录下的文件tu.txt。
文件路径:可以显式指出其绝对路径,如上面的"D:\\"或者"D:/"等。如果没有显式指出其路径,默认认为当前路径。也就相对路径。
数据的输入和输出几乎伴随着每个C语言程序,所谓输入就是从"源端"获取数据,所谓输出可以理解为向"终端"写入数据。这里的源端可以是键盘、鼠标、硬盘、光盘、扫描仪等输入设备,终端可以是显示器、硬盘、打印机等输出设备。在C语言中,把这些输入和输出设备也看作"文件"。

1.2 C语言文件系统中的类型

FILE:对象类型,足以保有控制 C I/O 流所需的全部信息
fpos_t:非数组完整对象类型,足以唯一指定文件的位置和多字节剖析状态
每个 FILE 对象直接或间接保有下列信息:
●  (C95)字符宽度:未设置、窄或宽。
●  (C95)多字节与宽字符间转换的分析状态(mbstate_t类型对象)
●  缓冲状态:无缓冲、行缓冲、全缓冲。
●  缓冲区,可为外部的用户提供缓冲区所替换。
●  I/O 模式:输入、输出或更新(兼具输入与输出)。
●  二进制/文本模式指示器。
●  文件尾指示器。
●  错误状态指示器。
●  文件位置指示器,可作为fpos_t类型对象访问,对于宽流包含剖析状态。
●  (C11)在多个线程读、写、寻位或查询流时避免数据竞争的再入锁。

1.3 预定义标准流

● stdin 与标准输入流关联的 FILE* 类型表达式
● stdout 与标准输出流关联的 FILE* 类型表达式
● stderr 与标准错误输出流关联的 FILE* 类型表达式

1.4 宏常量

2.流的概念及分类

        I/O设备的多样性及复杂性,给程序设计者访问这些设备带来了很大的难度和不便。为此,ANSIC的I/O系统即标准I/O系统,把任意输入的源端或任意输出的终端,都抽象转换成了概念上的“标准I/O设备”或称“标准逻辑设备”。程序绕过具体设备,直接与该“标准逻辑设备”进行交互,这样就为程序设计者提供了一个不依赖于任何具体I/O设备的统一操作接口,通常把抽象出来的“标准逻辑设备”或“标准文件”称作“流”。
把任意I/O设备,转换成逻辑意义上的标准I/O设备或标准文件的过程,并不需要程序设计者感知和处理,是由标准I/O系统自动转换完成的。故从这个意义上,可以认为任意输入的源端和任意输出的终端均对应一个“流”。
●流按方向分为:输入流和输出流。从文件获取数据的流称为输入流,向文件输出数据称为输出流。
●流按数据形式分为:文本流和二进制流。文本流是ASCII码字符序列,而二进制流是字节序列。
●流是一种抽象的概念,负责在数据的产生者和数据的使用者之间建立联系,并管理数据的流动。

3.文本文件和二进制文件到底有什么区别:

根据文件中数据的组织形式的不同,可以把文件分为:文本文件和二进制文件。
● 文本文件:把要存储的数据当成一系列字符组成,把每个字符的 ASCII 码值存入文件中。每个 ASCII 码值占一个字节,每个字节表示一个字符。故文本文件也称作字符文件或 ASCII 文件,是字符序列文件。
● 二进制文件:把数据对应的二进制形式存储到文件中,是字节序列文件。

4.C语言与文件读写

文件库函数stdio.h链接:http://www.cplusplus.com/reference/cstdio/
C语言操作文件分为三步,1)打开文件,2)读写文件,3)关闭文件。

4.1 打开文件函数原型:FILE * fopen ( const char * filename, const char * mode ); 

函数参数: 
filename:文件名,包括路径,如果不显式含有路径,则表示当前路径。例如,"D:\\text.txt"表示D盘根目录下的文件text.txt文件。
mode:文件打开模式,指出对该文件可进行的操作。常见的打开模式如"r"表示只读,"w"表示只写,"rw"表示读写,"a"表示追加写入。
返回值:
打开成功,返回该文件对应的 FILE 类型的指针;打开失败,返回 NULL。故需定义 FILE 类型的指针变量,保存该函数的返回值。可根据该函数的返回值判断文件打开是否成功。

4.2 关闭函数fclose的原型:int fclose(FILE* stream);

函数参数
stream:指向要关闭流对象的指针。
返回值:
如果流被成功关闭,返回0值。失败时,返回EOF(-1)。即使调用失败,作为参数传递的流将不再与文件或其缓冲区关联。

4.3 字符串格式化函数原型int sprintf(char* str, const char* format, ...);

函数参数
str:指向缓冲区指针,缓冲区足够大。
format:格式化字符串,该字符串遵循与printf中的格式相同的规范。
...:附加参数(根据格式化字符串的不同,函数可能需要一系列附加参数,每个参数都包含一个值,用于替换格式字符串中的格式说明符)。
返回值:
如果成功,将返回写入的字符总数。此计数不包括自动附加在字符串末尾的额外空字符。失败返回负数。

注意:Windows OS 上的 C 流在输出时将'\n'转换为'\r\n',输入时将'\r\n'转换为'\n'。

4.4 格式化写入函数int fprintf ( FILE * stream, const char * format, ... );

输出函数
int printf ( const char * format, ... );
示例:

 

4.5 从流中读取格式化数据函数int fscanf(FILE* stream, const char* format, ... );

函数参数
stream:指向文件对象的指针,该对象标识要从中读取数据的输入流。
format:格式化字符串,该字符串遵循与scanf中的格式相同的规范。
返回值
成功赋值的接收参数的数量(可以为零,在首个接收用参数赋值前匹配失败的情况下),或者若输入在首个接收用参数赋值前发生失败,则为EOF。

#include <stdlib.h>
#include <stdio.h>
int main()
{const int n = 10;int ar[n]={0};int i = 0;FILE *fpr = fopen("Test.txt","r");if(NULL == fpr){printf("open file failter \n");exit(EXIT_FAILURE);}for(i = 0;i<n;++i){fscanf(fpr,"%d ",&ar[i]);}fclose(fpr);fpr = NULL;return 0;
}

4.6 二进制文件的读写

        块数据写入函数:size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
函数参数:
ptr:这是指向要被写入的元素数组的指针。
size:这是要被写入的每个元素的大小,以字节为单位。
count:这是元素的个数,每个元素的大小为 size 字节。
stream:这是指向 FILE 对象的指针,该 FILE 对象指定了一个输出流。
返回值:
返回成功写入元素的个数,若出现错误或到达文件末尾,则可能小于 count。如果返回的数值与 count 参数值不同,则写入错误将阻止函数完成。在这种情况下,将为流设置错误指示器(ferror)。
块数据读出函数:size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
函数参数:
ptr:指向大小至少为(size*count)字节的内存块的指针,从流中读出的数据存储到ptr指向的内存。
size:读取元素的大小,unsigned int。
count:读取取元素的个数。
stream:是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。
返回值:
返回成功读取的对象个数,若出现错误或到达文件末尾,则可能小于 count。若 size 或 count 为零,则 fread 返回零且不进行其他动作。fread 不区分文件尾和错误,因此调用者必须用 feof 和 ferror 才能判断发生了什么。

#include <stdlib.h>
#include <stdio.h>
#define ARSIZE 10void Save_Ar(int *ar, int n)
{FILE *fpw = NULL;int len = 0;if(NULL == ar || n < 1) return ;fpw = fopen("Test2.txt", "wb");if(NULL == fpw){printf("open file failure \n");exit(EXIT_FAILURE);}len = fwrite(ar, sizeof(int), n, fpw);fclose(fpw);fpw = NULL;
}void Load_Ar(int *br, int n)
{FILE *fpr = NULL;int len = 0;if(NULL == br || n < 1) return;fpr = fopen("Test2.txt", "rb");if(NULL == fpr){printf("open file failure \n");exit(EXIT_FAILURE);}len = fread(br, sizeof(int), n, fpr);fclose(fpr);fpr = NULL;
}int main()
{int ar[ARSIZE] = {12, 23, 34, 45, 56, 67, 78, 89, 90, 100};int br[ARSIZE] = {0};int n = ARSIZE;Save_Ar(ar, n);Load_Ar(br, n);return 0;
}

5.缓冲和非缓冲文件系统

        在ANSI C标准中,使用的是“缓冲文件系统”。所谓缓冲文件系统指系统自动地在内存为每一个正在使用的文件名开辟一个缓冲区,从内存向磁盘输出数据必须先送到内存中的缓冲区,装满后再一起送到磁盘去。反向也是如此。vs2012 stdio.h中的FILE结构体:

 int fflush( FILE *stream );
功能:清除读写缓冲区,在需要立即把输出缓冲区的数据进行物理写入时
函数说明
如果指针指向一个输出流或者是一个最近的一次操作不是输入的更新流,输出刷新将会创造任意未写入的数据给将要被写入文件的流和最近的数据被修改流,并且最后的文件状态改变应该被标记为更新的基础文件的时间戳。
对于打开以使用基础文件描述进行读取的流,如果文件尚未处于EOF,并且该文件是能够搜索的文件,则基础打开文件描述的文件偏移量应设置为流的文件位置,并且任何未被从流中读取的 ungetc () 或 ungetwc () 推回到流上的字符都将被丢弃(不再进一步改变文件偏移量)。
如果 stream 是空指针,则 fflush () 将对上面定义了行为的所有流执行此刷新操作。
返回值
如果成功刷新, fflush 返回 0。指定的流没有缓冲区或者只读打开时也返回 0 值。返回 EOF 指出一个错误。
注意:如果 fflush 返回 EOF,数据可能由于写错误已经丢失。当设置一个重要错误处理器时,最安全的是用 setvbuf 函数关闭缓冲或者使用低级 I/O 例程,如 open、close 和 write 来代替流 I/O 函数。
其他用法
fflush(stdin)刷新标准输入缓冲区,把输入缓冲区里的东西丢弃[非标准]
fflush(stdout)刷新标准输出缓冲区,把输出缓冲区里的东西打印到标准输出设备上
注意事项
C 和 C++ 的标准里从来没有定义过 fflush(stdin)。也许有人会说:"可是我用 fflush(stdin) 解决了这个问题,你怎么能说是错的呢?" 的确,某些编译器(如 VC6)支持用 fflush(stdin) 来清空输入缓冲,但是并非所有编译器都要支持这个功能(linux 下的 gcc 就不支持),因为标准中根本没有定义 fflush(stdin)。
MSDN 文档里也清楚地写着:fflush on input stream is an extension to the C standard ( fflush 操作输入流是对 C 标准的扩充)。
以下是 C99 对 fflush 函数的定义:int fflush(FILE *stream);
如果 stream 指向输出流或者更新流 (update stream),并且这个更新流最近执行的操作不是输入,那么 fflush 函数将把任何未被写入的数据写入 stream 指向的文件(如标准输出文件 stdout)。否则, fflush 函数的行为是不确定的。 fflush (NULL) 清空所有输出流和上面提到的更新流。如果发生写错误, fflush 函数会给那些流打上错误标记,并且返回 EOF,否则返回 0。
由此可知,如果 stream 指向输入流(如 stdin),那么 fflush 函数的行为是不确定的。故而使用 fflush(stdin) 是不正确的。

void setbuf(FILE *stream, char *buffer);
功能:设置用于流操作的内部缓冲区。其长度至少应该为BUFSIZ个字符。
若buffer非空,则等价于setvbuf(stream,buffer,_IOFBF,BUFSIZ)
若buffer为空,则等价于setvbuf(stream,NULL,_IOBNF,0),这会关闭缓冲。
参数:
stream:要设置缓冲区的文件流
buffer:指向文件流所用的缓冲区的指针。若提供空指针,则关闭缓冲。
返回值无。
注解
若BUFSIZ不是适合的缓冲区大小,则能用setvbuf更改它。
setvbuf亦应当用于检测错误,因为setbuf不指示成功或失败。
此函数仅可在已将stream关联到打开的文件后,但要在任何其他操作(除了对setbuf/setvbuf的失败调用)前使用。
一个常见错误是设置stdin或stdout的缓冲区为生存期在程序终止前结束的数组:

int main(void) 
{char buf[BUFSIZ];setbuf(stdin,buf);
} //buf的生存期结束,未定义行为
int main()
{ char buff[256]; int a = 10, b = 20; FILE *pf = fopen("yhp.txt","w"); setbuf(pf,buff); fprintf(pf,"a = %d b = %d \n",a,b); fclose(pf); pf = NULL; return 0; 
}

函数原型
int setvbuf( FILE *stream, char *buffer, int mode, size_t size );
功能
以 mode所指示值更改给定文件流 stream的缓冲模式。
缓冲策略
​​若 buffer为空指针​​:重设内部缓冲区大小为 size。
​​若 buffer非空指针​​:指示流使用始于 buffer而大小为 size的用户提供缓冲区。
必须在 buffer所指向的数组的生存期结束前(用 fclose关闭流)。
成功调用 setvbuf后,数组内容不确定,任何使用它的尝试是未定义行为。
参数
​​stream​​:要设置缓冲的文件流。
​​buffer​​:指向要使用的流缓冲区的指针;若仅更改大小和模式则为空指针。
​​mode​​:使用的缓冲模式(可选值):
_IOFBF:​​全缓冲​​(当缓冲区为空时从流读入数据;缓冲区满时向流写入数据)。
_IOLBF:​​行缓冲​​(每次从流中读入一行数据或向流中写入一行数据)。
_IONBF:​​无缓冲​​(直接从流读入或写入数据;缓冲设置无效)。
​​size​​:缓冲区的大小。
返回值
成功时返回 0。失败时返回​​非零值​​。
注意
此函数仅可在已将 stream关联到打开的文件后使用(在任何其他操作前,除对 setbuf/setvbuf的失败调用)。实际缓冲区大小可能向下取整(如到 2 的倍数、页面大小的倍数等);并非所有 size字节都用于缓冲。​​行缓冲限制​​:多数实现中,行缓冲(_IOLBF)仅对终端输入流可用。
​​一个常见错误是设置stdin或stdout的缓冲区为生存期在程序终止前结束的数组:

// 错误示例:局部数组作缓冲区导致未定义行为
int main(void) {char buf[BUFSIZ];setvbuf(stdin, buf, _IOFBF, BUFSIZ);
} // buf 的生存期结束,后续操作未定义

        期待默认缓冲区大小BUFSIZ为实现上文件I/O的最高效缓冲区大小,但POSIX fstat经常提供更好的估计。

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

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

相关文章

Opencv C# 重叠 粘连 Overlap 轮廓分割 (不知道不知道)

先上效果图一种基于凹陷检测重叠轮廓分割的方法这两个星期压力大的一批&#xff0c;心脏都给干得乱跳了&#xff0c;现在高血压心率不齐贫血。兄弟们保重身体啊。简单说下逻辑&#xff1a;前处理&#xff1a;的噼里啪啦我就不说了&#xff0c;根据样品来(灰度&#xff0c;滤波&…

CentOS7 安装 rust 1.82.0

CentOS7 安装 rust 1.82.0 我在CentOS7.9中安装rust遇到报错版本低&#xff0c;再升级版本的过程中遇到诸多问题&#xff0c;简单记录。 遇到的问题 提示版本低 centos7 安装 ERROR: Rust 1.75.0 or newer required.Rust version 1.72.1 was found.原因是 CentOS7 的默认的软件…

Compose 适配 - 键鼠模式

一、概念不止触摸交互&#xff0c;在 ChromeOS 或外接键鼠的设备上&#xff0c;需要考虑焦点、悬停、右键等操作逻辑。二、使用2.1 焦点使用 Tab 键来导航&#xff0c;改变边框以提供清晰的焦点指示器。Composable fun Demo() {val interactionSource remember { MutableInter…

征服 Linux 网络:核心服务与实战解析

在当今的IT基础设施中&#xff0c;Linux作为服务器操作系统的基石&#xff0c;其强大的网络功能是其不可或缺的优势。对于任何志在成为高级系统管理员或运维工程师的人来说&#xff0c;精通Linux网络配置与服务管理是核心竞争力。 与日常应用不同&#xff0c;Linux网络管理往往…

Spark 之 DataFrame

# foreach useFeatureDF.rdd.foreachPartition {iter => iter.foreach {row =>val userId = row.getAs[Int]

射频信号(大宽高比)时频图目标检测anchors配置(下)

书接上文&#xff1a; 射频信号&#xff08;大宽高比&#xff09;时频图目标检测anchors配置&#xff08;上&#xff09; 三、4090加成检测效果深度优化 在4090 24G专用显存加持下继续探究大宽高比目标检测的奥秘&#xff1a; Conda环境迁移至租的云服 在云服上第一次测试…

跨境支付入门~国际支付结算(区块链篇)

摘要Web3区块链技术架构解析&#xff1a;从底层共识到应用生态本文系统梳理了Web3作为稳定币基础设施的技术架构&#xff0c;采用"数字共和国"的比喻框架&#xff0c;将区块链技术分解为六大核心模块&#xff1a;宪法根基&#xff08;区块链层&#xff09;&#xff1…

Docker 私服

什么是 Docker 私服&#xff1f; Docker 官方的 Docker Hub 是一个用于管理公共镜像的仓库&#xff0c;我们可以从上面拉取镜像 到本地&#xff0c;也可以把我们自己的镜像推送上去。 但是&#xff0c;有时候我们的服务器无法访问互联网&#xff0c;或者你不希望将自己的镜像…

DeepSeek vs ChatGPT:谁更胜一筹?

新兴 AI 聊天机器人的崛起与挑战&#xff1a;对话模型发展观察近年来&#xff0c;生成式人工智能领域持续取得突破&#xff0c;聊天机器人作为其中的代表&#xff0c;广泛应用于写作、编程、问答和信息处理等任务。2025 年初&#xff0c;国内某 AI 团队宣布了多项模型技术进展&…

飞算科技:以原创技术为翼,赋能产业数字化转型

在数字经济浪潮席卷全球的当下&#xff0c;一批专注于技术创新的中国企业正加速崛起&#xff0c;飞算数智科技&#xff08;深圳&#xff09;有限公司&#xff08;简称 “飞算科技”&#xff09;便是其中的佼佼者。作为一家国家级高新技术企业&#xff0c;飞算科技以自主创新为核…

电商接口什么意思?

“电商接口”这四个字&#xff0c;在中文互联网上出现的频次越来越高&#xff1a;商家后台、小程序、ERP、数据大屏……几乎任何与线上零售沾边的场景都会提到它。然而&#xff0c;对大多数刚进入电商行业的新人&#xff0c;甚至一些已经开了很多年网店的老板来说&#xff0c;这…

前端面试专栏-前沿技术:30.跨端开发技术(React Native、Flutter)

&#x1f525; 欢迎来到前端面试通关指南专栏&#xff01;从js精讲到框架到实战&#xff0c;渐进系统化学习&#xff0c;坚持解锁新技能&#xff0c;祝你轻松拿下心仪offer。 前端面试通关指南专栏主页 前端面试专栏规划详情 跨端开发技术&#xff08;React Native、Flutter&am…

复盘—MySQL触发器实现监听数据表值的变化,对其他数据表做更新

文章目录 MySQL交换数据库表中两列的值(额外的知识) 为防止后面有疑问,提前解释为什么需要 `$$` ? 第一版需求 第二版需求 第三版需求 注意事项: 存在的严重问题 最终版 关键修复说明: 完整测试场景: 额外建议(如果需要显式处理NULL): COALESCE函数 业务中出现的问题…

SpringCloud【Sentinel】

1&#xff0c;工作原理 2&#xff0c;常见规则 流量控制&#xff08;FlowRule&#xff09; 1&#xff0c;阈值类型设置如下 单机均摊&#xff1a;每个机器均摊&#xff0c;比如阈值填5&#xff0c;三个机器&#xff0c;就个机器都可以有5个 总体阈值&#xff1a;所有机器总阈…

解构未来金融:深入剖析DeFi与去中心化交易所(DEX)的技术架构

今天&#xff0c;我们来聊一个颠覆传统金融界的热门话题——DeFi&#xff08;去中心化金融&#xff09;。大家可能听说过它如何承诺将银行、交易所、保险等金融服务构建在一个开放、无需许可的区块链网络上。而这一切魔法的核心&#xff0c;正是其独特的“技术架构”。 在这篇文…

中国西北典型绿洲区土壤水分特征(2018-2019年)

数据集摘要该数据包含张掖绿洲黑河沿岸湿地、过渡带杨树林土壤水分、温度数据。数据采集时间为2018年至2019年&#xff0c;采集地点为张掖绿洲&#xff0c;数据为日数据。该数据集是按照课题制定的试验方案和中国生态系统研究网络编著的陆地生态系统水土气生观测规范进行数据的…

MySQL高可用部署

目录 一、MHA&#xff08;一主多从模式&#xff09; 1.环境准备&#xff08;所有节点&#xff09; 2. 部署 MySQL 主从复制&#xff08;MasterSlave&#xff09; 3.部署 MHA Manager&#xff08;管理节点&#xff09; &#xff08;1&#xff09;安装 MHA Manager &#xf…

从 XSS 到 Bot 攻击:常见网络攻击防不胜防?雷池 WAF 用全场景防护为网站筑牢安全墙

1. 网络攻击类型当前常见的网络攻击类型包括&#xff1a;重放攻击&#xff08;HTTP Request Replay Attack&#xff09;&#xff1a;攻击者截获合法用户的 HTTP 请求并重新发送&#xff0c;以欺骗服务器执行相同操作。危害包括消耗服务器资源、大量抓取数据或绕过认证操作敏感接…

【王树森推荐系统】推荐系统涨指标的方法05:特殊用户人群

为什么要特殊对待特殊人群&#xff1f; 新用户&#xff0c;低活用户的行为很少&#xff0c;个性化推荐不准确。个性化的召回和排序都需要基于用户的历史行为&#xff0c;如果历史行为少&#xff0c;个性化就做不好&#xff0c;尤其是新用户&#xff0c;这就需要策略把个性化做的…

Java 大视界 -- Java 大数据在智能家居能源管理与节能优化中的深度应用(361)

Java 大视界 -- Java 大数据在智能家居能源管理与节能优化中的深度应用&#xff08;361&#xff09;引言&#xff1a;正文&#xff1a;一、Java 构建的智能家居能源数据架构1.1 多源能耗数据实时采集1.2 家庭能源画像与异常检测二、Java 驱动的节能策略与智能控制2.1 多场景节能…