C# C语言中对文件的使用(小白必看!!!)

为什么会有文件

在写代码的过程中,我们写的数据是存储在电脑的内存中的,当程序结束和退出时,内存回收,我们写的数据也会随执行丢失,当再次运行程序时,是看不到上一次运行程序时的数据的,而文件可将数据进行持久化的保存。

二进制文件和文本文件

数据在文件中存储的形式有2种:

  • 数据不加转换直接以二进制的形式存储在文件中,该文件就叫二进制文件
  • 在存入文件前,将二进制形式的数据转换成ASCII码值的形式,再存入文件中,该文件就叫文本文件
    注意:字符以ASCII码值的形式进行存储,数值型数据可以转换成ASCII码值的形式存储,也可以以二进制的形式进行存储
    以1000为例:
    在这里插入图片描述
    1000在文本文件和二进制文件中存储是下面这样的:
    在这里插入图片描述
    VS中如何打开文本文件:
    在这里插入图片描述
    vs中如何打开二进制文件:
    在这里插入图片描述

流和标准流

  1. 流的概念

当我们将数据输出到各种外部设备,或者从各种外部设备中输入数据时,因设备不同,输出和输入的操作也就不同,为方便程序员操作,就提出了个抽象的概念,我们可以想象成河流,一条运输字符的河流。

下面借助画图板来方便大家理解:
在这里插入图片描述
c语言针对文件,画面,键盘等将数据进行输入或输出都是通过流操作的,对数据进行输入或输出时,都要先打开流,之后再关闭流。

  1. 标准流

当我们在键盘上输入数据,在显示屏上输出数据时,其实已经在使用流了,在c程序中,用scanf函数输入和printf函数输出数据时,直接默认打开标准流了。

  • stdin——标准输入流,在键盘上输入数据时,默认打开stdin,scanf函数就可在打开的标准流中输入数据。
  • stdout——标准输出流,大多数环境输出至显示屏上,printf函数就是将信息输出到标准输出流中。
  • stderr——标准错误流,将出现的错误输出到显示屏上。

默认打开标准输入输出流,是程序员在使用scanf和printf等函数时就可以进行输入和输出的操作了

文件指针

每个被使用的文件(各种外部设备)都在内存中开辟了相应的文件信息区,用来存放文件的信息(如:文件名,文件状态等),这些信息都被保存在一个结构体变量中,该结构体类型是由系统声明的,取名为FILE。

如下面画图板所示:
在这里插入图片描述
可以看出,通过访问文件信息区就可以访问相应的文件了

那该如何访问文件信息区呢?我们可以通过创建文件指针变量来访问

FILE *pf;//通过得到文件信息区的地址,来访问文件信息区

在这里插入图片描述
在前面所说的标准流:stdin,stdout,stderr,其实它们的类型也为FILE*
在这里插入图片描述

从上面介绍得知,当我们从键盘上输入数据,到输出至屏幕时,文件指针stdin,stdout是默认打开的,也就是把我们的流打开,打开之后就可访问我们的外部设备,而当我们想要访问其他各种文件时,我们需要定义一个指向FILE类型数据的指针变量,如:pf,来存放文件信息区的地址,然后通过文件指针变量来间接访问与它相关联的文件。
stdin,stdout,stderr是标准流,系统默认自动打开,而程序员自己定义的文件指针变量不是标准流,需要程序员手动打开

文件的打开和关闭

1. 打开文件
fopen——该函数的功能就是打开文件
函数定义如下:

FILE* fopen(const char* filename,const char* mode);
//第一个参数代表文件名,第二个参数代表文件的打开方式
//文件打开成功,则返回有效指针,否则返回NULL

示例1:以写的方式打开文件
在这里插入图片描述
示例2:以读的方式打开文件:
在这里插入图片描述
代码在这:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    FILE *pf = fopen("test.txt","w");
    if(pf == NULL)
    {
        perror("fopen");//若文件打开失败,则会报错
        return 1;
    }
    // ....写文件
    return 0;
}

2. 关闭文件
fclose——该函数的功能是关闭文件
函数定义如下:

void fclose (FILE *stream);
//参数代表要关闭的文件

文件在使用之后,就要关闭文件这是必要的

代码如下:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    //打开文件
    FILE *pf = fopen("test.txt","w");
    if(pf == NULL)
    {
        perror("fopen");//若文件打开失败,则会报错
        return 1;
    }
    // ....写文件
    //关闭文件
    fclose(pf);
    pf == NULL;//pf一定要置为空指针,不然将会变成野指针,这很危险
    return 0;

还有一些其他的打开方式,大家可自行上网查阅。

文件的读写

站在内存的角度看:

  • 读文件是从外部设备获取数据内存中
  • 写文件是从内存中输出数据到外部设备

下面是一些读文件和写文件所需的函数:

在这里插入图片描述

  • 示例1:

1.运用fputc(写字符)函数,进行写文件

fputc的定义:

int fputc (int character,FILE *stream);
//第一个参数代表要写的字符
//第二个参数代表要写的文件

运用:

#include <stdio.h>
#include <stdlib.h>
int main()
{
     //打开文件
	FILE* pf = fopen("test.txt", "w");//注意:进行的是写文件的程序,所以要以写的方式打开文件
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	else
	{
	    //将abcd写入文件中
		fputc('a', pf);
		fputc('b', pf);
		fputc('c', pf);
		fputc('d', pf);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

结果:
在这里插入图片描述
2.运用fgetc(读字符)函数,进行读文件

fgetc定义如下:

int fgetc (FILE *stream);
//将要读的文件写入参数中
//正常时,返回值是读到的字符的ACSII码值
//失败时,返回EOF(文件结束标志)

将刚刚写进去的abcd从文件中读出来

#include <stdio.h>
#include <stdlib.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");//以读的方式打开文件
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	int ch = 0;//接收返回的ASCII码值
	while ((ch = fgetc(pf)) != EOF)
	{
		printf("%c ", ch);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

结果:
在这里插入图片描述

  • 示例2:

1. 运用fputs(写字符串)函数,进行写文件

fputs定义如下:

int fputs (const char* str,FILE *stream);
//第一个参数代表要写的字符串的地址

运用:

int main()
{
	//打开文件
	FILE * pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	char arr[] = "abcdefg\n";
	fputs(arr, pf);
	char str[] = "i am student";
	fputs(str, pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

结果:
在这里插入图片描述

2. 运用fgtes(读字符串)函数,进行读文件

fgets定义如下:

char * fputs(char* str,int num,FILE * stream);
//第一个参数代表要读到的目标地址
//第二个参数代表要读的个数
//返回的是目标地址的首地址

注意:在进行读字符串时,程序只会读取(num - 1)个字符,最后一个num用来存放‘\0’;在遇到\n时,系统也会进行读取,读取完\n之后,系统会直接在其后添上‘\0’.
代码如下:

int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");//文件中存放的是abcdefg
	//此时文件中放的是abcdefg
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	char arr[20] = "xxxxxxxxxxxxxxxxxx";
	fgets(arr, 7, pf);//只读取7个字符
	printf("%s", arr);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

监视窗口:
在这里插入图片描述
我们可以看到系统只读取了6个字符,最后一个num存放的是‘\0’,并没有去读到我们的字符g

所以输出的结果是:abcdef

当文件中存储的是:
abcde
fg
一共存储了两行字符

代码如下:

int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	char arr[20] = "xxxxxxxxxxxxxxxxxx";
	fgets(arr, 7, pf);
	printf("%s", arr);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

监视窗口:
在这里插入图片描述
可知,遇到\n时也会将其读取到内存中
输出结果:abcde

  • 示例3:

1. 运用fprintf(将格式化数据写入文件)函数,进行写文件
fprintf的定义:

int fprintf(FILE* stream,const char* format,...);
//第二个参数代表格式化数据
//成功时,返回写入字符的个数,否则返回负数

运用:

struct S
{
	char name[20];
	int age;
	float score;
};
int main()
{
	//打开文件
	FILE * pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	struct S s = { "lili",19,98.5f };
	fprintf(pf,"%s %d %.1f\n", s.name, s.age, s.score);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

结果:
在这里插入图片描述
2. 运用fcanf(将文件中的格式化数据读到文件中)函数,进行读文件
fscanf的定义:

int fscanf(FILE* stream,const char* format,...);

使用:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
struct S
{
	char name[20];
	int age;
	float score;
};
int main()
{
	//打开文件
	FILE * pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	struct S s = { 0 };
	fscanf(pf,"%s %d %f", s.name, &(s.age), &(s.score));
	printf("%s %d %.1f\n", s.name, s.age, s.score);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

结果:
在这里插入图片描述

  • 示例4:

1.运用fwrite(将二进制数据写到文件中)函数,进行写文件
fwrite的定义:

size_t fwrite(const void*ptr,size_t size,size_t count,FILE* stream);
//参数意思是,将ptr中count个,大小为size个字节的数据,写到文件中
//返回值是写入的总数

使用:

int main()
{
	struct S s = { "cuihua",18,98.2 };
	FILE *pf = fopen("test.txt", "wb");
	if (pf == NULL)
	{
		perror(fopen);
		return 1;
	}
	else
	{
		fwrite(&s, sizeof(struct S), 1, pf);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

结果:以打开二进制文件的方式进行打开
在这里插入图片描述

2.运用fread(将二进制数据读到内存中)函数,进行读文件
fread的定义:

size_t fread(void *ptr,size_t size,size_t count,FILE* stream);

使用:

struct S
{
	char name[20];
	int age;
	float score;
};

int main()
{
	struct S s = { 0 };
	FILE* pf = fopen("test.txt", "rb");
	if (pf == NULL)
	{
		perror(fopen);
		return 1;
	}
	else
	{
		fread(&s, sizeof(struct S), 1, pf);
		printf("%s %d %.1f\n", s.name, s.age, s.score);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

结果:
在这里插入图片描述
文件的随机读写

  • fseek——根据文件的起始位置和偏移量来定位文件内容的光标

fseek的定义:

int fseek(FILE* stream,long int offset,int origin);
//第一个参数代表要读写的文件
//第二个参数代表偏移量(可正可负)
//第三个参数代表起始位置
//成功时,返回0,否则返回非0

起始位置分3种情况:
文件中的内容为:下面的三种情况以该文件的内容为例
在这里插入图片描述

  1. SEEK_SET(光标位于文件开头)
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fseek(pf, 4, SEEK_SET);//偏移量为4
	int ret = fgetc(pf);
	printf("%c\n", ret);
	return 0;
}

输出结果:e

  1. SEEK_CUR(光标位于文件的当前位置)
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fseek(pf, 4, SEEK_SET);//光标位于e的位置
	int ret = fgetc(pf);
	printf("%c\n", ret);
	fseek(pf, 1, SEEK_CUR);从e的位置开始偏移
	int t = fgetc(pf);
	printf("%c\n",t);
	return 0;
}

输出结果:e和g

  1. SEEK_END(光标位于文件末尾)
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fseek(pf, -4, SEEK_END);//光标从末尾开始往前偏移4个偏移量,负数是往前偏移
	int ret = fgetc(pf);
	printf("%c\n", ret);
	return 0;
}

输出结果:d

ftell——计算文件指针相较于文件起始位置的偏移量
(当不知道光标的位置时,可使用该函数)

定义:

long int ftell(FILE *stream);
int main()
{
	FILE* pf = fopen("test.txt", "r");
	//文件中的内容为abcdefg
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fseek(pf, 4, SEEK_SET);//读到的字符是e,读完之后的光标位于e的后面
	int ret = fgetc(pf);
	printf("%c\n", ret);
	long int num = ftell(pf);//所以结果为5
	printf("%ld\n", num);
	return 0;
}

输出结果:e和5

rewind——让指针回到起始位置

定义:

void rewind(FILE *stream);
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	rewind(pf);//将光标回到文件的起始位置
	int ret = fgetc(pf);
	printf("%c\n", ret);
	return 0;
}

输出结果:a

c程序中对文件的使用的基础就讲到这啦,创作不易,希望能得到大家的喜欢,一起学习吧!

  • 23
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值