C语言-文件操作

article/2025/9/17 10:29:25

当程序的生命周期结束,在内存中存放的数据就会随着内存的释放而清除,这并不满足我们日常生活中的记录需求,所以C语言开发了文件操作模式,通过将数据存放在硬盘,数据库等方式,实现数据的持久化。

文件存在于磁盘中,按照文件功能的角度来看一般分为两类:程序文件与数据文件。

程序文件:包括源文件(.c),目标文件(windows环境下.obj)与可执行文件(windows环境下.exe)。

数据文件:文件的内容不一定是程序,而是程序运行时读写的数据,数据文件的职能为提供给程序文件数据或者报存程序文件运行所产生的数据。

文件名:文件名(文件标识)分为三部分:文件路径+文件名主干+文件后缀

例如:c:\code\test.txt 其中c:\code\ 为文件路径 test为文件名主干 .txt为文件后缀

注意:文件路径指的是从盘符到该文件所经历的路径中各符号名的集合

文件的打开和关闭

文件类型指针:简称为文件指针。每个被使用的文件都在内存中开辟了一个相应的文件信息区,该区中存放对应文件的相关信息(文件名,大小等),这些信息被保存在一个由系统自定义的结构体类型(FILE)的变量中。

不同的C编译器中FILE类型中成员变量不完全相同,但一般大同小异。

每打开(或创建)一个文件时,系统会创建相应的FILE变量并在其中填充对应信息。

对于文件操作函数来说,很多函数的类型都是FILE*,所以我们可以创建临时变量FILE* pf承接函数返回值。通过文件指针变量能找到与其对应的文件。

文件在读写之前应该先打开文件,使用之后关闭文件。

ANSIC规定使用fopen函数打开文件,fclose函数关闭文件。

FILE* fopen(const char* filename,const char* mode)

filename-文件名,mode-打开方式。在打开文件时,fopen会创建一个对应该文件的文件信息区并返回信息区的首地址,打开失败则返回NULL。如:

 以读方式打开了一个名为test.txt的文件,并将此文件的指针传给临时变量pf,并检查fopen是否打开文件成功。

失败原因:1.可能没有能对应该文件名的文件。

2.有些系统会默认隐藏文件拓展名,所以命名的时候需要注意。

3.若想要打开的文件是另一储存路径下的同名的文件(打开的文件不在程序产生的文件中),应该写全需要打开的文件的路径(又叫绝对路径)。

关闭文件函数: int fclose(FILE* stream)

如上在程序最后 fclose(pf); 把文件指针pf对应的文件关闭。

再用 pf=NULL; 防野指针。

全部打开方式:

 

 使用w(写文件)方式打开一个文件时,如果该文件之前存在并有内容,则该文件会被先销毁再创建,内容也会清空。

‘b’其实是一种描述方式,意为对文件进行二进制操作,wb表示对文件以二进制写入形式打开,rb表示对文件以二进制读入方式打开。

文件的顺序读写
函数:

 

字符输出函数:int fputc(int c,FILE* stream);

c可以是整型,也可以是字符(或其他整型家族的成员)。用法:

 结果:在pf所指的文件中有a到z的字符串。

字符输入函数:int fgetc(FILE* stream);

返回值为读到的字符的ASCLL码值,如果文件读取完毕或者读取错误会返回EOF。用法:

从刚刚写入a到z字符的文件中从前往后读取,最终结果就为打印a到z的全部字符(即文件里的所有内容)。

注意:读取的位置会随着函数的使用次数增加自动向后移动,无序附加操作。

此处引入新概念::在外部设备上层创建出来,程序会通过流来读取通过外部设备产生的数据。

外部设备(键盘,屏幕,U盘,硬盘,网卡...)。

文件流:

标准输入流 stdin 键盘

标准输出流 stdout 屏幕

标准错误流 stderr 屏幕

注意:只要有一个C程序运行起来,这三个文件流会自行打开。

getchar只针对标准输入流stdin(键盘)。即使对stdin重定向,getchar针对的也只是stdin。f系列的输入输出函数都是作用于所有流的。

其他函数:

fgetc(stdin)就意味着该函数可从键盘上直接读取数据并作为函数的返回值返回。fgetc(stdin)运行时以字符为单位,从文件中读取一个字符。

fputs("wdkavbrk",pf);作用为将这个字符串写入对应文件中,不自带换行功能,若要实现换行可在字符串末尾加上转义字符'\n',如: fputs("wdkavbrk\n",pf);

char* fgets(char* string,int n,FILE* stream);将stream所指文件中的前n个字符放到string所指地址开始的n个空间中。(碰到换行符号或者终止符会提前结束)(返回值为string的首地址,读取失败返回NULL)

fprintf函数:用法:

fprintf函数相较于printf函数只多了一个FILE*类型的参数

首先在main之前创建了结构体类型,创建变量之后打开文件,用fprintf将结构体写入pf对应文件中,关闭文件,程序的结果为对应文件中有经fprintf规定的输入格式与数据。

fscanf函数:用法:

相较于scanf函数只多了一个FILE*类型的参数

 将文件中的数据按照scanf中对应格式取出并送到对应变量地址中。

sprintf函数:用法:

 sprintf相较于printf前多了一个char*类型的参数,作用为将printf中格式即相应数据全部转化为字符并输入到char*参数所指的地址中。(遇到换行或终止符会提前停止)

sscanf函数:

相较于scanf多了一个char*类型的参数,按格式(空格分割字符串内容)从字符串中提取数据并送到最后的变量列表中。

 各函数对比:

 

二进制输入函数:size_t fread(const void*buffer,size_t size,size_t count,FILE* stream)返回值为完整的读取出来的元素的个数,搭配打开文件方式(rb),将文件中count个size大小的空间的数据以二进制数据的读取方式读出并输入进buffer对应地址中。

 

二进制输出函数:size_t fwrite(const void*buffer,size_t size,size_t count,FILE* stream)

 需要搭配打开文件方式(wb)将从地址buffer向后检索,每个空间长为size,检索count个空间,并将这些空间中的内容(以二进制码的形式)输入到pf对应文件中。

文件的随机读写:

fseek函数:

因为无论是读是写还是其他对文件的操作,操作后其位置会往后移一位,所以有SEEK_CUR(即指向文件指针当前的位置)这个概念。SEEK_END-文件末尾的位置即文件最后一个字符的后一位。SEEK_SET-文件开始位置为文件的第一个字符的位置。

偏移量为目标位置减去当前位置所得值,如1表示目标位置在此位置之后1个位置,-1则表示目标位置在此位置之前一个位置。

若以w形式打开文件并写入abcd,则当前所在位置为d后面一个位置,若想要打印字符b,就可以写char ch=fseek(pf,-3,SEEK_CUR);经此操作之后文件指针当前位置指向b后面一位。

其他函数

ftell函数:long ftell(FILE* pf);返回值为当前文件指针所指位置对于文件开始位置的偏移量。

rewind函数:void rewind(FILE* stream);让文件指针的位置回到文件的起始位置

文本文件与二进制文件(根据数据的组织形式划分)

文本文件:我们能看得懂的文件。在外存上以ASCLL码的形式存储。

二进制文件:因为数据在内存中以二进制码存储,如果不转换直接将这些数据输出到外存,那这些数据不能直接看懂。

注意:字符在内存中一律按ASCLL码形式存储,数值可以使用ASCLL存储方式也可以使用二进制存储方式。

文件读取结束的判定

被错误使用的feof

feof只能用来确定结束的原因而不是结束的判定准则。

正确的判定手段为根据函数的返回值来判断。或者有些二进制函数返回的是运用字符的个数,可以通过这些字符的个数与已知文件字符的个数来判断是否结束。

int feof(FILE* stream);如果feof返回非空值,则说明文件遇到EOF正常结束。

int ferror(FILE* stream);如果ferror函数返回值非空,则说明文件因为遇到错误结束。

文件缓冲区:

ANSIC标准采用缓冲文件系统处理数据文件,该系统会在内存中为每一个正在使用的文件创建文件缓冲区,数据在内存中使用,当数据需要存到硬盘时先经过对应文件的缓冲区,缓冲区填满则将缓冲区里的数据全部送入硬盘中,从硬盘中取出数据也是如此。这种传输方式可提高操作系统的效率。缓冲区的大小根据C编译系统决定。

若想将未填满的缓冲区中内容直接输入进硬盘中可用fflush(pf);。使用fclose(pf);时也可以将剩余内容送入硬盘。通常会使用这两个函数来防止数据缺漏。

 


http://chatgpt.dhexx.cn/article/7UxZM8VI.shtml

相关文章

C语言打开文件详解

C语言中操作文件之前必须先打开文件;所谓“打开文件”,就是让程序和文件建立连接的过程。 打开文件之后,程序可以得到文件的相关信息,例如大小、类型、权限、创建者、更新时间等。在后续读写文件的过程中,程序还可以记…

一 形参与实参

1 实际参数(实参) 真实传给函数的参数,叫实参。即在函数调用时写入的实际参数。 实参可以是:常量、变量、表达式、函数等。无论实参是何种类型的量,在进行函数调用时,它们必须有确定的值,以便把…

【C语言函数参数详解】——实际参数(实参)形式参数(形参)

文章目录 一.什么是实际参数(实参)二.什么是形式参数(形参)三.形参与实参的关系 这篇文章我们一起学习一下函数的参数,函数的参数分为实参和形参。 一.什么是实际参数(实参) 首先我们来学习实…

java 静态工厂_高效Java第一条考虑用静态工厂代替构造函数

获得类的实例: 1.提供一个公有的构造函数; 2.提供一个公有的静态工厂方法,该方法只是一个返回类的实例的静态方法。 静态工厂方法与设计模式中的工厂方法模式不同。 提供静态工厂方法的优势——静态工厂方法与构造函数不同的第一大优势在于&a…

【算法之高效求素数】浅析求素数算法

注意: 如果没有特殊说明, 以下讨论的都是针对n为素数时的时间复杂度 1. 根据概念判断: 如果一个正整数只有两个因子, 1和p&#xff0c;则称p为素数. 代码: bool isPrime(int n) {if(n < 2) return false;for(int i 2; i < n; i)if(n%i 0) return false;return true;…

求素数算法

注意: 如果没有特殊说明, 以下讨论的都是针对n为素数时的时间复杂度 1. 根据概念判断: 如果一个正整数只有两个因子, 1和p&#xff0c;则称p为素数. 代码: bool isPrime(int n) {if(n < 2) return false;for(int i 2; i < n; i)if(n%i 0) return false;return true;…

求素数算法-网摘

摘自&#xff1a;http://www.cnblogs.com/luluping/archive/2010/03/03/1677552.html 浅析求素数算法注意: 如果没有特殊说明, 以下讨论的都是针对n为素数时的时间复杂度1. 根据概念判断:如果一个正整数只有两个因子, 1和p&#xff0c;则称p为素数. 代码: bool isPrime(int n) …

用JAVA编写50以内的素数_java求50以内的素数

java求50以内的素数 [2021-02-01 12:46:22] 简介: python求100内的所有素数的方法&#xff1a;使用判断该数除了1和它本身以外不再有其他因数即可&#xff0c;代码为【i2 for i in range(2,100): if(i%j0):break else:num.append(i)】。相关免费学 php去除nbsp的方法&#xff…

浅析求素数算法

原文地址为&#xff1a; 浅析求素数算法 2009-12-05 16:15:31 阅读18 评论0 字号&#xff1a;大中小 浅析求素数算法时间: 2006-10-27注意: 如果没有特殊说明, 以下讨论的都是针对n为素数时的时间复杂度1. 根据概念判断:如果一个正整数只有两个因子, 1和p&#xff0c;则称p为…

Python中的所有运算符以及运算符的优先级

文章目录 前言一、算术运算符二、赋值运算符三、比较运算符四、逻辑运算符五、位运算符六、运算符的优先级案例实战总结 前言 运算符是一些人为定义的特殊符号&#xff0c;比如我们生活当中最常见的 、-、、&#xff0c;它们主要用于数学计算、比较大小和逻辑运算等等。那这些…

在c语言中逻辑运算符的优先级是,c语言中逻辑运算符优先级是什么?

c语言中逻辑运算符优先级由高到低依次是&#xff1a;&#xff01;(逻辑非)、&&(逻辑与)、||(逻辑或)。逻辑表达式的值为逻辑值&#xff1b;逻辑值分为逻辑真值和逻辑假值&#xff0c;在判断时&#xff0c;仅有零值被判断为逻辑假值(false)&#xff0c;一切非零值均可被…

算数运算符,比较运算符,逻辑运算符,赋值运算符,运算优先级

文章目录 1.算数运算符1.1注意事项2.关系运算符&#xff0c;比较运算符2.1注意事项 3.逻辑运算符3.1注意事项 4.赋值运算法4.1注意特点 5.运算优先级 1.算数运算符 package mainimport "fmt"func main() {//说明&#xff0c;如果运算的数都是整数&#xff0c;那么除后…

【C语言】运算符的优先级

目录 算术运算符&#xff1a; 关系运算符&#xff1a; 逻辑运算符 三种运算符优先级高低比较&#xff1a; 算术运算符&#xff1a; 5种算术运算符&#xff1a;, -, *, /, % 优先级&#xff1a;*&#xff0c;/&#xff0c;%大于&#xff0c;- 关系运算符&#xff1a; 6种…

逻辑运算符与++的使用与优先级差别

我们的教材通常会按级次区别优先级&#xff0c;如下图所示&#xff1a; 那对于一个简单的编程题&#xff1a; int a,b,c,y;abc1;y a||b&&c 此时输出结果为&#xff1a;y1,a2,b1,c1 按照逻辑运算符&&优先于||&#xff0c;结果不应该为2&#xff0c;2&#xff…

逻辑运算符、位运算符、移位运算符、三目运算符、运算符的优先级

一、逻辑运算符 &#xff1a;逻辑运算符的作用是用于连接布尔表达式的。 1、& &#xff08;与&#xff0c;并且&#xff09; 规律&#xff1a; 只有左右变量同时为true&#xff0c;那么结果才是true&#xff0c;否则就false。 2、| &#xff08;或&#xff0c;或者&…

C/C++逻辑运算符 | | 和 的优先级误区——优先级决定运算顺序吗?

C运算符优先级表&#xff1a; 根据这个表格&#xff0c;我们很容易得出结论&#xff1a;&&的优先级大于|| 下面看一段代码&#xff0c;来验证这个结论 #include<iostream> using namespace std; int main() {int x 3;int y 1 || (x 1) && (x 1);pr…

运算符的优先级顺序

运算符优先级口诀&#xff1a;单目算术位关系&#xff0c;逻辑三目后赋值。 单目&#xff1a; 、- - 算术&#xff1a;、-、*、/、% 位&#xff1a;位移运算符&#xff1a;<<&#xff08;左移位&#xff09;、>>&#xff08;带符号右移位&#xff09;、>>>…

c++运算符优先级归纳

C一共有 18个优先级&#xff0c;运算中按优先级进行性计算&#xff0c;当优先级相同时&#xff0c;根据结合性规则来决定。 结合性&#xff1a; 1.从左到右&#xff08;L-R&#xff09;&#xff1a;操作数和操作符结合的顺序大部分是从左到右结合性的&#xff0c;例如&#xff…

C++运算符的优先级

有括号的优先级最高&#xff0c;涉及对象的运算符&#xff1b; 自增自减&#xff0c;取值&#xff0c;取地址运算符&#xff0c;逻辑非&#xff0c;按位取反&#xff0c;强制类型转换&#xff0c;长度运算符 先乘除后加减 左移右移运算符 比较运算符、三目运算符 各类赋值运算…

运算符优先级

C语言中&#xff0c;运算符除了常见的三大类&#xff0c;算术运算符、关系运算符与逻辑运算符之外&#xff0c;还有一些用于完成特殊任务的运算符。 运算符的运算优先级共分为15 级&#xff0c;1 级最高&#xff0c;15 级最低。 在表达式中&#xff0c;优先级较高的先于优先级…