【c语言】文件操作,解开你的疑惑

文件操作

为什么使用文件

我们程序运行的数据是运行在内存中的,当成程序结束的时候,内存被回收,数据也就销毁了,等再次运行程序的时候,是看不到上次的数据的,所以我们要使用文件将数据保存。

什么是文件

保存在硬盘(磁盘)上的文件就是文件

文件的分类

我们一般把文件分为:

  1. 数据文件
  2. 程序文件

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

数据文件:文件内容不一定是程序,而是程序运行时读取的数据。

在这,我们只讨论数据文件

文件名

文件都有一个唯一的文件标识,以便用户识别和引用。为了方便称呼文件标识又成为文件名

文件名分为以下3个部分:

文件路径,文件名主干,文件后缀

如:c:\csdn\text.txt

  • c:\csdn\是文件路径
  • text是文件名主干
  • .txt是文件后缀

二进制文件和文本文件

根据数据的组织形式,将文件分为二进制文件文本文件
二进制文件 :数据在内存中是以二进制的补码的形式存储的,如果我们不加转换的将数据存储到文件中,那这个文件就是二进制文件
文本文件:如果我们将数据转换成ascll码的形式存储到文件中,那这个以ascll码字符形式存储的文件就是文本文件。

一个数在文件中是怎么存储的?

  • 字符一律按照ascll码形式存储
  • 数值型数据可以按照ascll码的形式存储也可以按照二进制的形式存储

举个例子:整数10000 ,它的二进制是:00000000000000000010011100010000,那么将他以二进制的形式存储时,就如下图,占4字节。

将10000以ascll码的形式存储:

1的ascll码为:49,转换成二进制就是:00110001

0的ascll码为:48,转换成二进制就是:00110000

共占5个字节

测试代码:

c 复制代码
int main()
{
    int a = 10000;
    FILE* pf = fopen("text.txt","wb");//以二进制的形式写入数据
    assert(pf);//判断是否打开成功
    fputc(a,pf);
    fclose(pf);//打开文件后要记得关闭文件
    pf = NULL;
    return 0;
}

我们看到文件里面的数据是一个看不懂的符号

当我们在vs下用二进制编辑器打开这个文本的时候会看到:00000000 10 27 00 00

前面的00000000我们不看,就来看10 27 00 00

将它转换成二进制会得到:0000 0000 0000 0000 0010 0111 0001 0000 对应:0 0 0 0 2 7 1 0,因为在vs下是小端存储,所以我们看到的是10 27 00 00

文件的打开与关闭

流与标准流

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

一般情况下,我们想要向流里写数据或者读取数据都是要打开流后再进行操作。

标准流

我们从键盘输入数据再输出到屏幕上就是打开了标准流。

你可能疑惑:我咋不记得我打开了标准流啊?

那是因为标准流都是默认打开的,在c语言执行的时候默认打开了三个流:

  • stdin,标准输入流
  • stdout,标准输出流
  • stderr,标准错误流

这三个流是默认打开的,所以我们使用printf、scanf函数时能输入输出数据。

stdin、stdout、stderr三个流的类型为:FILE*,文件指针

文件指针

缓冲⽂件系统中,关键的概念是"⽂件类型指针",简称"⽂件指针"。

每当打开一个文件的时都会在内存中开辟一个文件信息区,用来存放文件的相关信息的(文件名,文件状态,文件的当前位置)

这些信息是保存在⼀个结构体变量中的。该结构体类型是由系统声明的,取名FILE

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

c 复制代码
struct _iobuf {
 char *_ptr;
 int   _cnt;
 char *_base;
 int   _flag;
 int   _file;
 int   _charbuf;
 int   _bufsiz;
 char *_tmpfname;
 };
 typedef struct _iobuf FILE;

不同的C编译器的FILE类型包含的内容不完全相同,但是⼤同⼩异

我们可以创建一个文件指针:

c 复制代码
FILE*pf;

这里定义了一个指向文件信息区的文件指针变量pf,通过这个指针变量可以间接的访问相关文件。

文件的打开与关闭

在使用的文件时,需要先打开文件,最后再关闭文件。

再编写程序时,打开文件会返回一个FILE*类型文件指针,该指针指向该文件

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

c 复制代码
//打开⽂件
FILE * fopen ( const char * filename, const char * mode );//filename为文件指针,mode为文件的打开方式
 //关闭⽂件 
int fclose ( FILE * stream );
c 复制代码
#include<stdio.h>
int main()
{
	FILE*pf=fopen("text.txt","r");
	//....程序
	fclose(pf);
	return 0;
}

文件的打开方式有下面这些:

文件的顺序读写

顺序读写函数介绍

上面所讲"适用于所有流指标准流和其他流(如文件流)"。
fgetc函数

c 复制代码
int fgetc ( FILE * stream );

字符输入,对于键盘到程序来说,是从键盘输入到程序,对于文件到程序来说,是从程序输入到文件(也可称为读文件)

c 复制代码
#include<stdio.h>
int main()
{
	FILE*pf=fopen("text.txt","r");//以读的形式打开文件,如果文件存在,则打开成功,否在打开失败
	if(pf=NULL)//判断文件是否打开成功
	{
	perror("fopen");//打印错误信息
	return 1;//打开失败就提前结束程序
	}
	int ch=0;
	ch=fgetc(pf);//fgetc函数的返回类型为int型
	printf("%c",ch);//输出到屏幕
	fclose(pf);
	pf=NULL;
	return 0;
}

假设这个文件中存放了一个字符a,那么这个字符a将被读取然后赋值到ch中在输出到屏幕上。

fputc函数

c 复制代码
int fputc ( int character, FILE * stream );

输出字符,从程序输出到文件中。

c 复制代码
int main()
{
	FILE*pf=fopen("text.txt","w");//以写的形式打开文件,如果文件存在,则删除原来的内容后写入数据,如果不存在,则创建新文件
	if(pf=NULL)
	{
		perror("fopen");
		return 1;
	}
	fputc(c,pf);//向文件写入一个字符c
	fclose(pf);
	return 0;
}

对于顺序读写,是根据光标来的

当写入\读取一个数据后,光标会后移一位,对于读取文件,当读取到文件末尾时,会返回EOF,这表示文件读取结束。

我们可以通过EOF来循环读取文件:

c 复制代码
#include<stdio.h>
int main()
{
	FILE*pf=fopen("text.txt","r");//以读的形式打开文件,如果文件存在,则打开成功,否在打开失败
	if(pf=NULL)//判断文件是否打开成功
	{
	perror("fopen");//打印错误信息
	return 1;//打开失败就提前结束程序
	}
	int ch=0;
	while((ch=fgetc(pf))!=EOF)//fgetc函数的返回类型为int型
	{
	printf("%c",ch);//输出到屏幕
	}
	fclose(pf);
	pf=NULL;
	return 0;

剩下的函数读者可自行去了解,用法于上面两个函数相差不大,这边我推荐一个网站来了解学习c语言相关函数
cplusplus

文件的随机读写

函数 声明
fseek int fseek ( FILE * stream, long int offset, int origin );
ftell long int ftell ( FILE * stream );
导管 void rewind ( FILE * stream );

fseek函数

根据文件指针的位置和偏移量来定位文件指针

c 复制代码
int fseek ( FILE * stream, long int offset, int origin );
offset为便宜量
origin为文件指针位置

 - SEEK_SET,文件起始位置
 - SEEK_CUR,文件当前位置
 - SEEK_END,文件末尾
c 复制代码
int main()
{
    FILE* tmp = fopen("text.txt","r");
    int ch = fgetc(tmp);
    printf("%c\n",ch);
    fseek(tmp,2,SEEK_CUR);
    ch = fgetc(tmp);
    printf("%c\n",ch);
    fseek(tmp,-3,SEEK_END);
    ch = fgetc(tmp);
    printf("%c",ch);
    return 0;
}

假设文件中的内容有:abcdefg,那么读到的内容为"a" "d"以及"b"。

ftell函数

返回⽂件指针相对于起始位置的偏移量

c 复制代码
 long int ftell ( FILE * stream );
c 复制代码
int main()
{
   
    FILE* tmp = fopen("text.txt","r");
    int ch = fgetc(tmp);
    printf("%c\n",ch);
    fseek(tmp,2,SEEK_CUR);
    ch = fgetc(tmp);
    printf("%c\n",ch);
    fseek(tmp,-3,SEEK_END);
    ch = fgetc(tmp);
    printf("%c\n",ch);

    printf("%ld",ftell(tmp));//输出4

    return 0;
}

rewind函数

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

c 复制代码
 void rewind ( FILE * stream );

文件读取结束的判定

feof函数

用来判断文件结束的原因是不是因为读取到文件末尾

记住,feof函数不是用来判断文件是否读取结束的

文件缓冲区

ANSIC标准采用"缓冲文件系统"处理数据文件。简单来讲就是:打开文件时内存会开辟一块相应的文件缓冲区,当读取或写入数据时会先将数据放到缓冲区,等缓冲区空间满后在刷新缓冲区将数据读取到程序或者写入到文件中。缓冲区的大小由编译器决定。

因为有缓冲区的存在,C语⾔在操作⽂件的时候,需要做刷新缓冲区或者在⽂件操作结束的时候关闭⽂件,如果不做,可能导致读写文件失败的问题。(关闭文件时会刷新缓冲区)

干兴趣的可以通过这段代码观察一下文件 的读写

相关推荐
Am心若依旧40923 分钟前
[c++11(二)]Lambda表达式和Function包装器及bind函数
开发语言·c++
明月看潮生25 分钟前
青少年编程与数学 02-004 Go语言Web编程 20课题、单元测试
开发语言·青少年编程·单元测试·编程与数学·goweb
大G哥35 分钟前
java提高正则处理效率
java·开发语言
stm 学习ing35 分钟前
HDLBits训练5
c语言·fpga开发·fpga·eda·hdlbits·pld·hdl语言
VBA63371 小时前
VBA技术资料MF243:利用第三方软件复制PDF数据到EXCEL
开发语言
轩辰~1 小时前
网络协议入门
linux·服务器·开发语言·网络·arm开发·c++·网络协议
小_太_阳1 小时前
Scala_【1】概述
开发语言·后端·scala·intellij-idea
向宇it1 小时前
【从零开始入门unity游戏开发之——unity篇02】unity6基础入门——软件下载安装、Unity Hub配置、安装unity编辑器、许可证管理
开发语言·unity·c#·编辑器·游戏引擎
古希腊掌管学习的神2 小时前
[LeetCode-Python版]相向双指针——611. 有效三角形的个数
开发语言·python·leetcode
赵钰老师2 小时前
【R语言遥感技术】“R+遥感”的水环境综合评价方法
开发语言·数据分析·r语言