前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C语言读写程序文件-学习三十二

C语言读写程序文件-学习三十二

作者头像
XG.孤梦
修改2022-08-05 09:05:09
8600
修改2022-08-05 09:05:09
举报
文章被收录于专栏:日志随记日志随记

顺序读写数据文件

  • 顺序写时,先写入的数据存放在文件中前面,后写入的数据存放在文件中后面
  • 顺序读时,先读文件中前面的数据,后读文件中后面的数据。
  • 顺序读写来说,对文件读写数据的顺序和数据文件中的物理顺序是一致的

读写一个字符的函数

  • fgetc()函数
  • 原型:int fgetc( FILE * fp );
  • 调用形式:fgetc(fp)
  • 作用:从 fp 所指向的输入文件中读取一个字符
  • 返回值:成功则返回的是读取的字符,发生错误则返回 EOF(即-1)。
  • fputc()函数
  • 原型:int fputc( int c, FILE *fp );
  • 调用形式:fputc(c,fp)
  • 功能:把参数 c 的字符值写入到 fp 所指向的输出流(文件)中
  • 返回值:写入成功,它会返回它会返回写入的字符(一个非负值),发生错误,则会返回 EOF(即-1)。
  • 例如:

从一个磁盘文本文件顺序读入字符并在屏幕上显示出来。

代码语言:c
复制
#include <stdio.h>
#include <string.h>

void main() {
	char c;
	FILE* fp = NULL;
	fopen_s(&fp, "a.txt", "r");
	c = fgetc(fp);
	while (c != EOF) {
		putchar(c);
		c = fgetc(fp);
	}
	fclose(fp);
}
75224-1ew4c9pntje.png
75224-1ew4c9pntje.png

  • feof()函数
  • 调用方式:feof(fp)
  • 功能:对于二进制文件读取时判断是否结束。
  • 返回值:如果是文件结束,函数feof()值为1(真);否则为0(假)。
  • 例如:

从一个磁盘二进制文件顺序读入字符并在屏幕上显示出来。

代码语言:c
复制
#include <stdio.h>
#include <string.h>

void main() {
	char c;
	FILE* fp = NULL;
	fopen_s(&fp, "a", "r");
	c = fgetc(fp);
	while (!feof(fp)) {
		putchar(c);
		c = fgetc(fp);
	}
	fclose(fp);
}
88474-zyynpa6v8r.png
88474-zyynpa6v8r.png

例子

从键盘输入一些字符,逐个把它们送到磁盘上去直到用户输入一个“#”为止。

代码语言:c
复制
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma warning (disable:4996)

void main() {
	char c,filename[10];
	FILE *fp = NULL;
	printf("请输入所用的文件名:");
	scanf("%s", filename);
	if ((fp = fopen(filename, "w")) == NULL) {
		printf("无法打开此文件\n");
		exit(0);
	}
	c = getchar(); // 接收执行scanf时最后输入的回车符
        // 如果注释掉,文件中会首先换行,然后再输入的字符串

	printf("请输入一个字符串(以#结束)");
		c = getchar(); // 第一个输入的字符被赋给变量c
		while (c!='#') {
			fputc(c, fp);
			putchar(c);  // 字符被输出到显示器
			c = getchar();
		}
		putchar(10); // 向屏幕输出一个换行符
	fclose(fp);
}
89309-s5xrri0082.png
89309-s5xrri0082.png

将一个磁盘文件中的信息复制到另一个磁盘文件中。今要求建立的a.txt文件中的内容复制到另一个磁盘文件b.txt中。

代码语言:c
复制
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma warning (disable:4996)


void main() {
	char c=NULL,infile[10],outfile[10];
	FILE *in = NULL;
	FILE *out = NULL;
	printf("请输入读取的文件名:");
	scanf("%s", infile);
	printf("请输入输出的文件名:");
	scanf("%s", outfile);
	if ((in = fopen(infile, "r")) == NULL) {
		printf("无法打开此文件\n");
		exit(0);
	}
	if ((out = fopen(outfile, "w")) == NULL) {
		printf("无法打开此文件\n");
		exit(0);
	}
	while (c!=EOF) {
		c= fgetc(in);
		fputc(c, out);
		putchar(c);  // 字符被输出到显示器
	}
	putchar(10); // 向屏幕输出一个换行符
	fclose(in);
	fclose(out);
}
12110-dua55umiv1.png
12110-dua55umiv1.png

读写一个字符串的函数

  • fgets()函数
  • 原型:char *fgets( char *buf, int n, FILE *fp );
  • 调用格式:char *fgets( str, n, fp );
  • 功能:从 fp 所指向的输入流(文件)中读取长度为(n - 1)的字符串存放到字符数组str中,并在最后追加一个 null 字符(即'\0')来终止字符串。
  • 返回值:读成功返回地址str ,失败则返回NULL
  • fputs()函数
  • 原型:int fputs( const char *s, FILE *fp );
  • 调用格式:int fputs( str, fp );
  • 功能:str所指向的字符串写到文件指针变量fp所指向的文件中。
  • 返回值:如果写入成功,则返回写出的字符个数(一个非负值),如果发生错误,则返回EOF(即-1)。
  • 说明:
  • fgets(str,n,fp);中 n 是要求得到的字符个数,但实际上只读 n-1 个字符,然后在最后加一个**\0**字符, 这样得到的字符串共有n个字符,把它们放到字符数组str中。
  • fgets()函数,如果在读完 n-1 个字符之前就遇到一个换行符 \n 或文件的末尾 EOF, 则读入结束,则只会返回读取到的字符,包括换行符
  • fputs函数中第一个参数可以是字符串常量、字符数组名或字符型指针。
  • fputs()函数字符串末尾的\0不输出。

例子

从键盘读入若千个字符串,然后把字符串送到磁盘文件中保存。

代码语言:c
复制
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma warning (disable:4996)

void main() {
	char str[3][10];
	int i;
	FILE *fp = NULL;
	printf("请输入要写入的字符串:\n");
	for (i = 0; i < 3; i++) {
		gets(str[i]);
	}
	if ((fp = fopen("a.txt", "w")) == NULL) {
		printf("无法打开此文件\n");
		exit(0);
	}
	for (i = 0; i < 3; i++) {
		fputs(str[i], fp);
		fputs("\n", fp);
		printf("写入成功:");
		printf("%s\n", str[i]);
	}
	fclose(fp);
}
63696-1a1qby8yyda.png
63696-1a1qby8yyda.png

读取文件中的字符串,打印到控制台

代码语言:c
复制
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma warning (disable:4996)

void main() {
	char str[3][10];
	int i;
	FILE *fp = NULL;

	if ((fp = fopen("a.txt", "r")) == NULL) {
		printf("无法打开此文件\n");
		exit(0);
	}
	for (i = 0; i < 3; i++) {
		fgets(str[i],10,fp);
		printf("%s", str[i]);
	}
	fclose(fp);
}
75177-bb3slgxub7v.png
75177-bb3slgxub7v.png

用格式化的方式读写文件

  • 一般调用方式为:
  • fprintf(文件指针, 格式字符串, 输出表列);
  • 例如:
  • fprintf(fp,"%d,%f",i,f);
  • fscanf(文件指针, 格式字符串, 输入表列);
  • 例如:
  • fscanf(fp,"%d,%f",&i,&f);
  • 用fprintf和fscanf对磁盘文件读写,使用方便,容易理解, 但是由于在输入时要将ASCII码转换为二进制形式,在输出时又要将二进制形式转换符,花费时间比较多。
  • 因此在内存与磁盘频繁交换的情况下,最好不要用 fprintf 和 fscanf 函数,可以用fread 和 fwrite 函数
二进制 I/O 函数
  • fread函数
  • 原型:size_t fread(void *buffer, size_t size, size_t count, FILE *a_file);
  • 返回值:如果读取成功,则返回读的块数,失败,则返回0 。
  • fwrite函数
  • 原型:size_t fwrite(const void *buffer, size_t size, size_t count, FILE *a_file);
  • 返回值:如果写入成功,则返回写的块数,失败,则返回0 。
  • 这两个函数都是用于存储块的读写 - 通常是数组或结构体。
例子:

从键盘输入5个学生的有关数据,然后把它们转存到磁盘文件上去,读取并打印到控制台。

代码语言:c
复制
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma warning (disable:4996)
#define SIZE 5

struct Student {
	int num;
	char name[10];
	int age;
	char addr[15];
}stu[SIZE];


void main() {
	void save();
	void reads();
	int i;
	printf("请输入学生数据:\n");
	for (i = 0; i < SIZE; i++) {
		scanf("%d %s %d %s", &stu[i].num, stu[i].name, &stu[i].age, stu[i].addr);
	}
	save();
	printf("学生信息:\n");
	reads();
}

void save() {
	int i;
	FILE *fp = NULL;

	if ((fp = fopen("stu.dat", "wb")) == NULL) {
		printf("无法打开此文件\n");
		return;
	}
	for (i = 0; i < SIZE; i++) {
		if (fwrite(&stu[i], sizeof(struct Student), 1, fp) != 1) {
			printf("写入文件错误\n");
		}
	}
	fclose(fp);
}

void reads() {
	int i;
	FILE *fp = NULL;

	if ((fp = fopen("stu.dat", "rb")) == NULL) {
		printf("无法打开此文件\n");
		return;
	}
	for (i = 0; i < SIZE; i++) {
		fread(&stu[i], sizeof(struct Student), 1, fp);
		printf("%4d %-10s %4d %-15s\n", stu[i].num, stu[i].name, stu[i].age, stu[i].addr);
	}
	fclose(fp);
}
00828-uhx8fhplria.png
00828-uhx8fhplria.png

从已有的二进制文件“stu2.dat”中,读入数据并输出到“stu.dat”文件中

代码语言:c
复制
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma warning (disable:4996)
#define SIZE 7

struct Student {
	int num;
	char name[10];
	int age;
	char addr[15];
}stu[SIZE];


void main() {
	void load();
	void save();
	void reads();
	load();
	save();
	printf("学生信息:\n");
	reads();
}

void save() {
	int i;
	FILE *fp = NULL;

	if ((fp = fopen("stu.dat", "wb")) == NULL) {
		printf("无法打开此文件\n");
		return;
	}
	for (i = 0; i < SIZE; i++) {
		if (fwrite(&stu[i], sizeof(struct Student), 1, fp) != 1) {
			printf("写入文件错误\n");
		}
	}
	fclose(fp);
}

void reads() {
	int i;
	FILE *fp = NULL;

	if ((fp = fopen("stu.dat", "rb")) == NULL) {
		printf("无法打开此文件\n");
		return;
	}
	for (i = 0; i < SIZE; i++) {
		fread(&stu[i], sizeof(struct Student), 1, fp);
		printf("%4d %-10s %4d %-15s\n", stu[i].num, stu[i].name, stu[i].age, stu[i].addr);
	}
	fclose(fp);
}

void load() {
	int i;
	FILE *fp = NULL;

	if ((fp = fopen("stu2.dat", "rb")) == NULL) {
		printf("无法打开此文件\n");
		return;
	}
	for (i = 0; i < SIZE; i++) {
		if (fread(&stu[i], sizeof(struct Student), 1, fp) != 1) {
			if (feof(fp)) {
				fclose(fp);
				return;
			}
			printf("无法打开此文件\n");
		}
	}
	fclose(fp);
}
13050-y668khnwvde.png
13050-y668khnwvde.png

  • 其它读写函数
  • putw 和 getw 函数
  • 作用:以二进制形式,对磁盘文件读写一个int型的整数,2个字节。
  • 返回值:成功,则返回所写的整数值;失败,则返回EOF
  • 例如:putw(10, fp); i=getw(fp);

随机读写数据文件

  • 对文件进行顺序读写比较容易理解,也容易操作,但有时效率不高。

文件位置标记

  • 为了对读写进行控制,系统为每个文件设置了一个文件读写位置标记(简称文件标记), 用来指示“接下来要读写的下一个字符的位置”。
  • 一般情况下,在对字符文件进行顺序读写时,文件标记指向文件开头,进行读的操作时,就读第一个字符,然后文件标记向后移动一个位置,在下一次读操作时,将位置标记指向第二个字符读入,以此类推直到遇文件尾结束。
  • 随机读写可以在任何位置读取和写入数据

文件位置标记的定位

  • 将文件的指针指向文件的开头,进行文件操作
  • rewind函数
  • 函数原型:void rewind(FILE *fp);
  • 功能:重置文件位置指针到文件开头。
  • 返回值:无

-例如:

代码语言:c
复制
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma warning (disable:4996)

void main(){ 
	FILE *fp1, *fp2;
	fp1 = fopen("file1.dat", "r");
	fp2 = fopen("file2.dat", "w");
	while (!feof(fp1)) {
		putchar(getc(fp1));
	}
	putchar(10);
	rewind(fp1); 
	while (!feof(fp1)) {
		putc(getc(fp1), fp2);
	}
	fclose(fp1);
	fclose(fp2); 
}
37619-mifij20l4sa.png
37619-mifij20l4sa.png

  • 可以强制使文件标记指向指定的位置
  • fseek函数
  • 调用形式:fseek(文件类型指针,位移量,起始点)
  • 起始点:0代表“文件开始位置(SEEK_SET)”,1为“文件当前位置(SEEK_CUR)”,2代表“文件的末尾(SEEK_END)”。
  • 位移量指以起始点为基点,向前移动的字节数。位移量应是long型数据(在数字的末尾加一个字母L)。
  • fseek函数一般用于二进制文件。
  • 例如:
代码语言:c
复制
    fseek(fp,100L,0);  // 将位置指针移动到离文件头100个字节处
    fseek(fp,50L,1);   // 离当前位置50个字节处
    fseek(fp,-10L,2);  // 从文件末尾处向后退10个字节

  • ftell函数
  • 由于文件中的文件位置标记经常移动,人们往往不容易知道其当前位置,所以常用ftell函数得到当前位置(相对于文件开头的位移量来表示)。 如果调用函数时出错(如不存在fp指向的文件),ftell函数返回值为-1L。
  • 例如:
  • i=ftell(fp);
  • if(i==-1L){printf("error\n");}

例子

在磁盘文件上存有10个学生的数据要求将第1,3,5,7,9个学生数据输入计算机,并在控制台显示出来。

代码语言:c
复制
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma warning (disable:4996)

struct Student {
	int num;
	char name[10];
	int age;
}stu[10];

void main() {
	FILE *fp;
	int i;
	if ((fp = fopen("stu.dat", "rb")) == NULL) {
		printf("打开文件失败");
		exit(0);
	}
	for (i = 0; i < 10; i+=2) {
		fseek(fp, i * sizeof(struct Student), 0);
		fread(&stu[i], sizeof(struct Student), 1, fp);
		printf("%4d %-10s %4d\n", stu[i].num, stu[i].name, stu[i].age);
	}
	fclose(fp);
}
62785-8ufmssrugo9.png
62785-8ufmssrugo9.png

文件读写的出错检测

  • ferror函数
  • 一般调用形式:ferror(fp);
  • 返回值:如果为0,表示未出错,否则表示出错。
  • 每次调用输入输出函数,都产生新的ferror函数值,因此调用输入输出函数后立即检查。
  • 调用fopen时,ferror的初始值自动置为0。

  • clearerr函数
  • 作用是使文件错误标志和文件结束标志置为0。
  • 调用一个输入输出函数时出现错误(ferror值为非零值),立即调用clearerr(fp), 使ferror(fp)值变0,以便再进行下一次检测
  • 只要出现文件读写错误标志,它就一直保留,直到对同一文件调用 clearerr 函数或 rewind 函数,或任何其他一个输入输出函数

总结
  • 在使用文件时,首先要定义一个文件指针:FILE *fp; 然后通过该指针来操作相应的文件;
  • 通过fopen这个函数,使文件指针fp和相应的文件建立了联系,通过fclose函数将切断fp和文件的联系;
  • 如果以一次一个字符的方式处理文件,需要用 fgetc 或者 fputc 函数;
  • 如果以一次一行的方式处理文件,可以用 fgets 或者 fputs 函数;
  • 如果以一次一个结构体的方式处理文件,可以用 freadfwrite 函数(多为二进制文件);

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-02-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 顺序读写数据文件
    • 读写一个字符的函数
      • 例子
    • 读写一个字符串的函数
      • 例子
    • 用格式化的方式读写文件
      • 二进制 I/O 函数
      • 例子:
  • 随机读写数据文件
    • 文件位置标记
      • 文件位置标记的定位
        • 例子
        • 总结
    • 文件读写的出错检测
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档