当前位置:网站首页>C语言进阶篇 六.文件的操作
C语言进阶篇 六.文件的操作
2022-07-24 05:16:00 【且随疾风前行->】
目录
1. 为什么使用文件
2. 什么是文件
文件即指磁盘上的文件,在程序设计中,通常指两类文件:
1.程序文件
2.数据文件
3. 文件的打开和关闭
在C语言中,提供了两个函数分别用于文件的打开和关闭。
FILE*fopen(constchar*filename,constchar*mode);
参数一filename是文件名,可以用像tt.txt这样的相对路径(相对于当前工程文件的目录下),也可以用像W:\a\tt.txt这样的绝对路径(注意\前加\才能表示\字符),因为类型是字符指针,故文件名要加“ ”,表示字符串首地址。
FILE* pf = fopen("W:\\a\\tt.txt", "w");//绝对路径
FILE* pf = fopen("tt.txt", "w");//相对路径
参数二mode是指文件的打开方式,有多种打开方式,如:

该函数的返回值是FILE*类型的文件指针,事实上这是一种结构体指针,原因是文件被使用时在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个系统定义过的结构体变量中的。
struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;
不同编译器的FILE类型包含的内容不完全相同。当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构体的变量,并初始化。这样一来,通过文件指针就能找到对应的文件。
当使用fopen函数打开文件失败时,函数会返回空指针。
于是可以这么使用:
FILE* pf = fopen("tt.txt", "w");
if (pf == NULL) {
perror("fopen->");
return 1;
}fclose(pf);
pf = NULL;4. 文件的顺序读写
常见读写的函数

fgetc函数可以从所有输入流(包括标准输入流(键盘))中返回字符的ASCII码值,读取后该文件指针会指向文件中下一个字符。
int fgetc ( FILE * stream );
如果读到文件末尾或者读取错误就会返回EOF,这个函数和getc等效,但是有些库getc是用宏实现的。
例如工程目录下在tt.txt,写字母a,然后用fgetc可以读取文件内容


fputc函数与这个函数相对,可以将字符输出到所有输出流中(包括标准输出流(屏幕)),输出后该文件指针会指向文件中下一个字符。
int fputc ( int character, FILE * stream );
如果写入成功,返回字符的ASCII码值,写入错误时返回EOF。
与fgetc,fputc对应的一组函数是fgets,fputs,不同的是输出和输入的是字符串,
char * fgets ( char * str, int num, FILE * stream );
从stream中读取num个字符(num包含了\0,实际就num-1个字符)拷贝到str指向的空间,在字符串结尾还会拷贝一个\0,直到遇到读到换行符或者文件结尾(EOF),如果读到换行符\n,会停止,把换行符也拷贝到str指向的空间。
fgets函数和gets不太一样,首先是参数个数,然后是gets不会拷贝\0到str中,gets不能指定拷贝的字符个数(可能会导致缓冲区溢出),而fgets可以指定拷贝个数。
使用实例:



以下实例证明确实拷贝了\0

以下两个函数,fscanf可以从所有输入流中(格式化)读取数据到文件中,二fprintf则可以从所有输出流格式化输出到文件中,使用过scanf和printf这组函数就明白了,只不过把屏幕换成了文件。 对比下函数参数易于学习。
int fscanf ( FILE * stream, const char * format, ... );
int scanf ( const char * format, ... );
int sscanf ( const char * s, const char * format, ...);
int fprintf ( FILE * stream, const char * format, ... );
int printf ( const char * format, ... );
int sprintf ( char * str, const char * format, ... );
sscanf函数可以从字符串中读取格式化数据,sprintf是把格式化数据写入到字符串中。
例如:
/* sscanf example */
#include <stdio.h>
int main ()
{
char sentence []="Rudolph is 12 years old";
char str [20];
int i;
sscanf (sentence,"%s %*s %d",str,&i);
printf ("%s -> %d\n",str,i);
return 0;
}注:scanf类函数中添加了*的部分会被忽略(跳过),不会被读取,也就是说上面函数从sentence字符串中读取了Rudolph字符串到str中,然后跳过了字符串is,然后读取了12到i中。(在printf中使用,*表示用后面的形参替代*的位置,实现动态格式输出,如printf("%.*s\n", 1, "abc");从字符串“abc”输出宽度为1的字符串,结果是a)
输出如下:

注意:如果把%*s去掉则读不到12了,如下

如果调整参数顺序,结果如下:

5. 文件的随机读写
上述函数只能在文件上顺序读写数据,要实现在文件各个位置读写可以借助下列函数。
int fseek ( FILE * stream, long int offset, int origin );
这个函数可以复位文件指针,调用函数便可以让它文件指针stream指向指定的位置。
参数origin是起始位置,可以是这些参数:
offset是相对起始位置的偏移量(字节数)。
使用实例:

要得到文件指针的当前位置可以借助ftell函数
long int ftell ( FILE * stream );
该函数返回当前文件指针相对文件起始位置的偏移量(字节数)。
使用实例:

rewind函数,可以将文件指针重新指向文件的起始位置 void rewind ( FILE * stream );
例如:(文件指针指向开头,所以ftell返回0 )
6. 文本文件和二进制文件
数据文件被分成了文本文件和二进制文件两种类型。
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
通常,ptr是数组名,size是数组元素的大小(所占字节数),count是输出的元素个数,于是可以这么用,例如:

以二进制的形式打开,会发现文件中是这样的数据:

7. 文件读取结束的判定
需要注意不能用feof的返回值判断文件是否读取结束和直接判断文件是否为空。
int feof ( FILE * stream );
如果文件指针指向的位置已经没有数据了返回非0,表文件结束,否则返回0,表示还有数据。



边栏推荐
- 熊市抄底指南
- 反射
- Hcip day 3 - mGRE experiment
- Embedded system transplantation [3] - uboot burning and use
- 纯小白教程 在idea里使用Druid数据库连接池
- jdbc封装一个父类减少代码重复
- Ren Xudong, chief open source liaison officer of Huawei: deeply cultivate basic software open source and jointly build the root technology of the digital world
- Token of space renewable energy
- T 6-10
- I'm interested in reading efficient reading - the most cost-effective self investment
猜你喜欢

酒店IPTV数字电视系统解决方案

【Pytorch】conv2d torchvision.transforms

AttributeError: ‘NoneType‘ object has no attribute ‘shape‘

Introduction to threads
![[Huang ah code] Introduction to MySQL - 3. I use select *, and the boss directly rushed me home by train, but I still bought a station ticket](/img/60/23fc79cf0e399265b4bd75159ad4d1.png)
[Huang ah code] Introduction to MySQL - 3. I use select *, and the boss directly rushed me home by train, but I still bought a station ticket

PPPoE网关模拟环境搭建

JMeter FAQs

jdbc封装一个父类减少代码重复

FTP file transfer protocol

IDEA:SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder“.
随机推荐
Introduction to reflection
明星逆市入局的NFT,如何能走出独立行情?
Embedded system transplantation [3] - uboot burning and use
anaconda常用命令的整理
[deep learning] (III) image classification
反射
Using a* heuristic search to solve maze routing problem
Relational database 10 minutes to understand MySQL
HCIA NAT experiment
MySQL连接
The network NN can calculate the NTCP provided by the host system
1. Pedestrian recognition based on incremental occlusion generation and confrontation suppression
文本摘要 ACL2021
【sklearn】数据预处理
C table data De duplication
BeanShell built-in variable CTX
[Huang ah code] Introduction to MySQL - 3. I use select *, and the boss directly rushed me home by train, but I still bought a station ticket
String的字符串常量池和intern()详解
The opening ceremony of the 2022 Huawei developer competition in China kicked off!
generator生成器,只生成两个方法