【C语言】文件操作

前言

我们先假设想一下如果没有文件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运行程序,是看不到上次程序的数据的,如果要将数据进行持久化的保存,我们可以使用文件,本篇就来探讨一下C语言有关文件的操作。

个人主页:小张同学zkf

若有问题  评论区见

感兴趣就关注一下吧

目录

1.什么是文件 

1.1 程序文件

1.2 数据文件

1.3 文件名

2.二进制文件和文本文件

3.文件的打开和关闭

3.1流和标准流

3.1.1流

 3.1.2标准流

3.2文件指针

3.3 文件的打开和关闭

4.文件的顺序读写

4.1顺序读写函数介绍

4.2fputc和fgetc

4.3fputs和fgets

4.4fread和fwrite

4.5对比一组函数

5.文件的随机读取

5.1fseek

5. 2ftell

5.3rewind

6. 文件读取结束的判定

6.1被错误使用的 feof

7. 文件缓冲区

 


1.什么是文件 

 磁盘(硬盘)上的文件是文件。 但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。

1.1 程序文件

程序文件包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。

1.2 数据文件

文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。
本章讨论的是数据文件。 在以前所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。
其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上文件。

1.3 文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含3部分: 文件路径+文件名主干+文件后缀
例如: c:\code\test.txt
为了方便起见,文件标识常被称为文件名

2.二进制文件和文本文件

根据数据的组织形式,数据文件被称为 文本文件 或者 二进制文件
数据在内存中以 二进制的形式存储 ,如果不加转换的输出到外存的文件中,就是二进制文件。
如果要求在外存上 以ASCII码的形式存储 ,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。
一个数据在文件中是怎么存储的呢?
字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。
如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节(VS2019测试)。

3.文件的打开和关闭

3.1流和标准流

3.1.1流

我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输入输出操作各不相同,为了方便程序员对各种设备进行方便的操作,我们抽象出了流的概念,我们可以把流想象成流淌着字符的河。

 3.1.2标准流

那为什么我们从键盘输入数据,向屏幕上输出数据,并没有打开流呢?
那是因为C语言程序在启动的时候,默认打开了3个流:
stdin - 标准输入流,在大多数的环境中从键盘输入,scanf函数就是从标准输入流中读取数据。
stdout - 标准输出流,大多数的环境中输出至显示器界面,printf函数就是将信息输出到标准输出流中。
stderr - 标准错误流,大多数环境中输出到显示器界面。
这是默认打开了这三个流,我们使用scanf、printf等函数就可以直接进行输入输出操作的。
stdin、stdout、stderr 三个流的类型是: FILE * ,通常称为 文件指针
C语言中,就是通过 FILE* 的文件指针来维护流的各种操作的。

3.2文件指针

缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名 FILE .

 例如,VS2013 编译环境提供的 stdio.h 头文件中有以下的文件类型申明:

struct _ iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _ iobuf FILE ;
不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。
每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信
息,使用者不必关心细节。
一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。
下面我们可以创建一个FILE*的指针变量:
FILE* pf; // ⽂件指针变量
定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够间接找到与它关联的文件。
比如:

 

3.3 文件的打开和关闭

文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。
在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。

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

// 打开⽂件
FILE * fopen ( const char * filename, const char * mode );
// 关闭⽂件
int fclose ( FILE * stream );

 mode表示文件的打开模式,下面都是文件的打开模式:

/* fopen fclose example */
#include <stdio.h>
int main ()
{
 FILE * pFile;
 //打开⽂件
 pFile = fopen ("myfile.txt","w");
 //⽂件操作
 if (pFile!=NULL)
 {
 fputs ("fopen example",pFile);
 //关闭⽂件
 fclose (pFile);
 }
 return 0;
}

4.文件的顺序读写

4.1顺序读写函数介绍

 

上面说的适用于所有输入流一般指适用于标准输入流和其他输入流(如文件输入流);所有输出流一般指适用于标准输出流和其他输出流(如文件输出流)。

4.2fputc和fgetc

 这个函数就是把字符写到文件里,若写入成功,返回的是这个字符的asc码值,若失败,返回EOF(-1)

这个函数就是把这个文件里的数据一个字符一个字符的读取出来,若读取成功,返回的是读取成功的字符的asc码值,若读取到文件末尾,返回EOF(-1)

4.3fputs和fgets

 fputs是以文本行的形式将字符串写入文件里,若写入成功,返回非负值,若失败,返回EOF(-1)

这个num是要在文件里读多少个字符,str是把字符读出来之后存放的地址,stream要读的文件

若读取成功,返回str,若失败,返回空指针

4.4fread和fwrite

ptr是存放要写入这个文件的指针,size是输入这个文件每个元素的字节大小,count是写入这个文件的个数,steam是要写入的文件,写进去的文件里的数据转换成二进制信息

返回成功写入文件的个数,若返回的个数与count不同,则写入失败

这个就和上面的刚好相反,把文件里的二进制数据以size每个元素字节大小和count个数读取到ptr指向的空间,返回的是成功读取的个数,若返回的数与count不同,则读取失败

4.5对比一组函数

scanf/fscanf/sscanf
printf/fprintf/sprintf

你会发现fprintf与fscanf参数与printf和scanf相比就前面多个文件指针参数,剩下的都一样,他们都是以指定格式写入文件或从文件读取

那sscanf与sprintf是什么那

sscanf就是把字符串读成格式化数据

sprintf就是把格式化数据转化成字符串

 


5.文件的随机读取

5.1fseek

有时候我们文件里的光标可能需要为我们移动到自己想要的位置,那该怎么做那

需要用到fseek函数 

功能:根据文件指针的位置和偏移量来定位文件指针(文件内容的光标)。 

int fseek ( FILE * stream, long int offset, int origin );

offset是偏移量,origin是起始位置,起始位置有三种情况:

#include <stdio.h>

int main ()
{
 FILE * pFile;
 pFile = fopen ( "example.txt" , "wb" );
 fputs ( "This is an apple." , pFile );
 fseek ( pFile , 9 , SEEK_SET );
 fputs ( " sam" , pFile );
 fclose ( pFile );
 return 0;
}

5. 2ftell

返回文件指针相对于起始位置的偏移量,就是计算偏移量的。
long int ftell ( FILE * stream );

#include <stdio.h>
int main ()
{
 FILE * pFile;
 long size;
 pFile = fopen ("myfile.txt","rb");
 if (pFile==NULL) 
 perror ("Error opening file");
 else
 {
 fseek (pFile, 0, SEEK_END); // non-portable
 size=ftell (pFile);
 fclose (pFile);
 printf ("Size of myfile.txt: %ld bytes.\n",size);
 }
 return 0;
}

5.3rewind

让文件指针的位置回到文件的起始位置

 void rewind ( FILE * stream );

#include <stdio.h>

 int main ()
 {
 int n;
 FILE * pFile;
 char buffer [27];
 
 pFile = fopen ("myfile.txt","w+");
 for ( n='A' ; n<='Z' ; n++)
 fputc ( n, pFile);
 rewind (pFile);
 
 fread (buffer,1,26,pFile);
 fclose (pFile);
 
 buffer[26]='\0';
 printf(buffer);
 return 0;
 }


6. 文件读取结束的判定

6.1被错误使用的 feof

很多人用feof是用来判断文件是否结束的,这是错误的!!!

牢记:在文件读取过程中,不能用feof函数的返回值直接来判断文件的是否结束。
feof 的作用是:当文件读取结束的时候,判断是读取结束的原因是否是: 遇到文件尾结束
文本文件读取是否结束,判断返回值是否为 EOF fgetc ),或者 NULL fgets
例如:
fgetc 判断是否为 EOF 
fgets 判断返回值是否为 NULL 
二进制文件的读取结束判断,
判断返回值是否小于实际要读的个数。
例如:
fread判断返回值是否小于实际要读的个数。

 

文本文件的例子:
# include <stdio.h>
# include <stdlib.h>
int main ( void )
{
int c; // 注意: int ,⾮ char ,要求处理 EOF
FILE* fp = fopen( "test.txt" , "r" );
if (!fp) {
perror( "File opening failed" );
return EXIT_FAILURE;
}
//fgetc 当读取失败的时候或者遇到⽂件结束的时候,都会返回 EOF
while ((c = fgetc(fp)) != EOF) // 标准 C I/O 读取⽂件循环
{
putchar (c);
}
// 判断是什么原因结束的
if (ferror(fp))
puts ( "I/O error when reading" );
else if (feof(fp))
puts ( "End of file reached successfully" );
fclose(fp);
}

二进制文件的例子:

# include <stdio.h>
enum { SIZE = 5 };
int main ( void )
{
double a[SIZE] = { 1. , 2. , 3. , 4. , 5. };
FILE *fp = fopen( "test.bin" , "wb" ); // 必须⽤⼆进制模式
fwrite(a, sizeof *a, SIZE, fp);
// double 的数组
fclose(fp);
double b[SIZE];
fp = fopen( "test.bin" , "rb" );
size_t ret_code = fread(b, sizeof *b, SIZE, fp); // double 的数组
if (ret_code == SIZE) {
puts ( "Array read successfully, contents: " );
for ( int n = 0 ; n < SIZE; ++n)
printf ( "%f " , b[n]);
putchar ( '\n' );
} else { // error handling
if (feof(fp))
printf ( "Error reading test.bin: unexpected end of file\n" );
else if (ferror(fp)) {
perror( "Error reading test.bin" );
}
}
fclose(fp);
}

7. 文件缓冲区

ANSIC 标准采用“缓冲文件系统” 处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的

这里可以得出一个结论:
因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。


结束语

本篇博客涉及知识多,小编也在尽力总结,可以采取对比记忆等方法记忆,文件操作有关知识就总结到这里吧

OK感谢观看!!!

         

  • 82
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 64
    评论
在现有省、市港口信息化系统进行有效整合基础上,借鉴新 一代的感知-传输-应用技术体系,实现对码头、船舶、货物、重 大危险源、危险货物装卸过程、航管航运等管理要素的全面感知、 有效传输和按需定制服务,为行政管理人员和相关单位及人员提 供高效的管理辅助,并为公众提供便捷、实时的水运信息服务。 建立信息整合、交换和共享机制,建立健全信息化管理支撑 体系,以及相关标准规范和安全保障体系;按照“绿色循环低碳” 交通的要求,搭建高效、弹性、高可扩展性的基于虚拟技术的信 息基础设施,支撑信息平台低成本运行,实现电子政务建设和服务模式的转变。 实现以感知港口、感知船舶、感知货物为手段,以港航智能 分析、科学决策、高效服务为目的和核心理念,构建“智慧港口”的发展体系。 结合“智慧港口”相关业务工作特点及信息化现状的实际情况,本项目具体建设目标为: 一张图(即GIS 地理信息服务平台) 在建设岸线、港口、港区、码头、泊位等港口主要基础资源图层上,建设GIS 地理信息服务平台,在此基础上依次接入和叠加规划建设、经营、安全、航管等相关业务应用专题数据,并叠 加动态数据,如 AIS/GPS/移动平台数据,逐步建成航运管理处 "一张图"。系统支持扩展框架,方便未来更多应用资源的逐步整合。 现场执法监管系统 基于港口(航管)执法基地建设规划,依托统一的执法区域 管理和数字化监控平台,通过加强对辖区内的监控,结合移动平 台,形成完整的多维路径和信息追踪,真正做到问题能发现、事态能控制、突发问题能解决。 运行监测和辅助决策系统 对区域港口与航运业务日常所需填报及监测的数据经过科 学归纳及分析,采用统一平台,消除重复的填报数据,进行企业 输入和自动录入,并进行系统智能判断,避免填入错误的数据, 输入的数据经过智能组合,自动生成各业务部门所需的数据报 表,包括字段、格式,都可以根据需要进行定制,同时满足扩展 性需要,当有新的业务监测数据表需要产生时,系统将分析新的 需求,将所需字段融合进入日常监测和决策辅助平台的统一平台中,并生成新的所需业务数据监测及决策表。 综合指挥调度系统 建设以港航应急指挥中心为枢纽,以各级管理部门和经营港 口企业为节点,快速调度、信息共享的通信网络,满足应急处置中所需要的信息采集、指挥调度和过程监控等通信保障任务。 设计思路 根据项目的建设目标和“智慧港口”信息化平台的总体框架、 设计思路、建设内容及保障措施,围绕业务协同、信息共享,充 分考虑各航运(港政)管理处内部管理的需求,平台采用“全面 整合、重点补充、突出共享、逐步完善”策略,加强重点区域或 运输通道交通基础设施、运载装备、运行环境的监测监控,完善 运行协调、应急处置通信手段,促进跨区域、跨部门信息共享和业务协同。 以“统筹协调、综合监管”为目标,以提供综合、动态、实 时、准确、实用的安全畅通和应急数据共享为核心,围绕“保畅通、抓安全、促应急"等实际需求来建设智慧港口信息化平台。 系统充分整合和利用航运管理处现有相关信息资源,以地理 信息技术、网络视频技术、互联网技术、移动通信技术、云计算 技术为支撑,结合航运管理处专网与行业数据交换平台,构建航 运管理处与各部门之间智慧、畅通、安全、高效、绿色低碳的智 慧港口信息化平台。 系统充分考虑航运管理处安全法规及安全职责今后的变化 与发展趋势,应用目前主流的、成熟的应用技术,内联外引,优势互补,使系统建设具备良好的开放性、扩展性、可维护性。
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 64
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值