C语言之文件详解

  1. 一般在程序设计中的文件类型有两种:程序文件、数据文件。

  2. 程序文件:包括源程序文件(.c)、目标文件(.obj)、可执行文件(.exe)

  3. 数据文件:该文件的内容不是程序,而是程序运行时读写的数据。本篇博客就是对数据文件的操作的讨论。

1.文件名

  • 文件名是一个文件的唯一标识,用于识别和引用该文件。
  • 文件名包含3个部分:文件路径+文件名主干+文件后缀
  • 如:D:\sheena\test.txt。

2.文件类型

  1. 文本文件:数据在内存中以二进制形式存储,若要求在外存上以ASCII码的形式存储,则需要存储前转换。该种以ASCII字符的形式存储的文件就是文本文件。
  2. 二进制文件:数据在内存中以二进制形式存储,若不加转换依旧以二进制形式的输出到外存中,该文件即二进制文件。

3.文件缓冲区

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

4.文件指针

  • 每个被使用的文件在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息,这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名为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 pf;
  • 可以通过文件指针变量找到与它关联的文件。

5.文件的打开关闭

  • 文件在读写之前应该先打开文件,在读写之后使用该文件结束之后应该关闭文件。

(1)数据文件的打开

  • fopen
  • FILE * fopen ( const char * filename, const char * mode );
  • 打开一个文件
  • 成功返回该文件的文件指针,失败返回空指针。

(2)数据文件的关闭

  • fclose
  • int fclose(FILE *stream);
  • 关闭一个文件
  • 成功返回0,失败返回EOF(文件结束标识符,-1)
//mode:打开方式
"r"(只读,覆盖写):为了输入数据,打开一个已经存在的文本文件。如果指定文件不存在则出错。

"w"(只写):为了输出数据,打开一个文本文件。如果指定文件不存在则建立一个新的文件。

"a"(追加写):向文本文件尾添加数据。如果指定文件不存在则出错。

"rb"(只读,覆盖写):为了输入数据,打开一个二进制文件。如果指定文件不存在则出错。

"wb"(只写):为了输出数据,打开一个二进制文件。如果指定文件不存在则建立一个新的文件。

"ab"(追加写):向一个二进制文件尾添加数据。如果指定文件不存在则出错。

"r+"(读写):为了读和写,打开一个文本文件。如果指定文件不存在则出错。

"w+"(读写):为了读和写,建立一个新的文件。如果指定文件不存在则建立一个新的文件。

"a+"(读写):打开一个文件,在文件尾进行读写。如果指定文件不存在则建立一个新的文件。

"rb+"(读写):为了读和写打开一个二进制文件。如果指定文件不存在则出错。

"wb+"(读写):为了读和写,新建一个新的二进制文件。如果指定文件不存在则建立一个新的文件。

"ab+"(读写):打开一个二进制文件,在文件尾进行读和写。如果指定文件不存在则建立一个新的文件。
#include <stdio.h>

int main()
{
	FILE *pf;
	pf = fopen("mytest.txt", "w");//以只写模式打开,若不存在该文件则创建。
	if (pf != NULL)
	{
		fclose(pf);
	}

	return 0;
}

6.文件的读写

(1)数据文件的顺序读写

①fgetc

  • int fgetc ( FILE * stream );
  • 字符输入函数,从文件中读取一个字符,适用于所有输入流。
  • 成功返回读取的字符(提升为int型),失败返回EOF(文件结束标识符,-1)
#include <stdio.h>

int main()
{
	FILE *pf;
	int c;
	pf = fopen("mytest.txt", "r");//以只读模式打开,上面已经创建了该文件。
	while ((c = fgetc(pf)) != EOF)
	{
		printf("%c ", c);
	}
	printf("\n");
	fclose(pf);

	return 0;
}

在这里插入图片描述
②fputc

  • int fputc ( int character, FILE * stream );
  • 字符输出函数,将字符输入到文件指针指向的指定文件中,适用于所有输出流。
  • 成功返回写入的字符(提升为int型),失败返回EOF(文件结束标识符,-1)
#include <stdio.h>

int main()
{
	FILE *pf;
	int c;
	pf = fopen("mytest.txt", "a");//以追加写模式打开,上面已经创建了该文件。
	fputc('I', pf);
	fclose(pf);
	pf = fopen("mytest.txt", "r");//以只读模式打开
	while ((c = fgetc(pf)) != EOF)
	{
		printf("%c ", c);
	}
	printf("\n");
	fclose(pf);

	return 0;
}

在这里插入图片描述
③fgets

  • char * fgets ( char * str, int num, FILE * stream );
  • 文本行输入函数,从文件中读取数据,读到换行符为止,适用于所有输入流。从文件中读到程序中。
  • 成功返回读到的字符串str,失败或读到文件结尾时返回NULL。
#include <stdio.h>

int main()
{
	FILE *pf;
	char str[100];
	pf = fopen("mytest.txt", "a");//以追加写模式打开,上面已经创建了该文件。
	fputc('I', pf);
	fclose(pf);
	pf = fopen("mytest.txt", "r");//以只读模式打开
    fgets(str, 12, pf);
	puts(str);

	fclose(pf);

	return 0;
}

在这里插入图片描述
④fputs

  • int fputs ( const char * str, FILE * stream );
  • 文本行输出函数,从程序中输出到文件中,向指定文件中写入字符串,适用于所有输出流。
  • 成功返回0,失败返回EOF。
#include <stdio.h>

int main()
{
	FILE *pf;
	char str[100];
	pf = fopen("mytest.txt", "a");//以追加写模式打开,上面已经创建了该文件。
	fputs(" am sheena", pf);
	fclose(pf);
	pf = fopen("mytest.txt", "r");//以只读模式打开
    fgets(str, 22, pf);
	puts(str);

	fclose(pf);

	return 0;
}

在这里插入图片描述
⑤fprintf

  • int fprintf ( FILE * stream, const char * format, … );
  • 格式化输出函数,将数据写到文件中,适用于所有输出流。
  • 成功返回输出的字符数,失败返回一个负值。
  • 和printf用法差不多,只不过fprintf的使用时需要指定写入的文件指针。
#include <stdio.h>

int main()
{
	FILE *pf;
	pf = fopen("mytest.c", "w");
	fputc('s', pf);
	fputs("\nsheena\n", pf);
	fprintf(pf,"语文:%d\n数学:%d\n英语:%d\n", 98, 110, 99);
	fclose(pf);

	return 0;
}

⑥fscanf

  • int fscanf ( FILE * stream, const char * format, … );
  • 格式化输入函数,对应fprintf,将文件中的数据输入到程序中显示,适用于所有输入流。
  • 与fgets区别在于:fscanf遇到换行和空格时结束,而fgets遇到空格不会结束。
  • 成功返回输入到程序中的字符个数,失败返回EOF。
  • 与scanf一样使用,只不过加一个要读的文件的文件指针。
#include <stdio.h>

int main()
{
	FILE *pf;
	int a, b, c;
	pf = fopen("mytest.c", "r");
	fscanf(pf,"语文:%d\n数学:%d\n英语:%d\n", &a, &b, &c);
	printf("%d,%d,%d\n", a, b, c);
	fclose(pf);

	return 0;
}

在这里插入图片描述
⑦fread

  • size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
  • 二进制输入,从一个文件中读数据,适用于文件。
  • 成功返回读取元素总数,失败或者读到文件末尾返回0。

⑧fwrite

  • size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
  • 二进制输出,将数据写入文件中,适用于文件。
  • 成功返回写入的元素的总数,失败返回0。
#include <stdio.h>
#include <string.h>
#include <assert.h>

struct TelInfo
{
	char _name[24];
	char _tel[16];
	int _age;
};
char *my_itoa(int n, char* buf)
{
	assert(buf);
	int i = 0;
	while (n)
	{
		buf[i] = n % 10 + '0';
		n /= 10;
		++i;
	}

	int begin = 0, end = i - 1;
	while (begin < end)
	{
		char tmp = buf[end];
		buf[end] = buf[begin];
		buf[begin] = tmp;
		++begin;
		--end;
	}
	buf[i] = '\0';
	return buf;
}
int main()
{
	struct TelInfo info;
	strcpy(info._name, "sheena");
	strcpy(info._tel, "153****5645");
	info._age = 20;
	FILE *fp = fopen("telinfo.c", "wb");
	fwrite(&info, sizeof(info), 1, fp);
	fclose(fp);

	struct TelInfo other;
	FILE *fp2 = fopen("telinfo.c", "rb");
	fread(&other, sizeof(other), 1, fp2);
	fclose(fp2);
	printf("%s,%s,%d\n", other._name, other._tel, other._age);

	return 0;
}

(2)数据文件的随机读写
①fseek

  • 根据文件指针的位置和偏移量来定位文件指针
  • int fseek ( FILE * stream, long int offset, int origin );
  • 成功返回0,失败返回非0。
//origin
不变	    参考位置
SEEK_SET	文件开始
SEEK_CUR	文件指针的当前位置
SEEK_END	文件结尾*
#include <stdio.h>

int main()
{
	FILE *pf;
	pf = fopen("test.c", "wb");
	fputs("I am Sheena", pf);
	fseek(pf, 9, SEEK_SET);
	fputs("hello", pf);
	fclose(pf);

	return 0;
}

在这里插入图片描述
②ftell

  • 得到文件指针相对于起始位置的偏移量
  • long int ftell ( FILE * stream );
  • 成功返回当前位置的偏移量,失败返回-1L。
#include <stdio.h>
//获取一个文件的大小
int main()
{
	FILE *pf;
	pf = fopen("test.c", "r");
	fseek(pf, 0, SEEK_END);
	long int sz = ftell(pf);
	printf("%d\n", sz);
	fclose(pf);

	return 0;
}

在这里插入图片描述
③rewind

  • 让文件指针的位置回到文件起始的位置。
  • void rewind ( FILE * stream );
  • 无返回值。
#include <stdio.h>

int main()
{
	FILE *pf;
	pf = fopen("test12.c", "w");
	fputs("hello world\n", pf);
	rewind(pf);
	fputs("sheena:\n", pf);
	fclose(pf);
	return 0;
}

在这里插入图片描述

7.文件结束符判定

  • 在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。而是应用于当文件读取结束时,判断是读取失败结束,还是读到文件末尾结束。
  • 文本文件:判断返回值是否为EOF(fgetc),NULL(fgets)
  • 二进制文件:判断返回值是否小于实际要读的个数。
#include <stdio.h>

int main()
{
	FILE *pf;
	pf = fopen("test12.c", "r");
	int c;
	while ((c = fgetc(pf)) != EOF)
		putchar(c);
	if (ferror(pf))
		puts("error");
	else if (feof(pf))
		puts("end of the file");
	fclose(pf);
	return 0;
}

在这里插入图片描述

8.文件操作的总结

#include <stdio.h>
#include <string.h>
#include <assert.h>

struct TelInfo
{
	char _name[24];
	char _tel[16];
	int _age;
};
char *my_itoa(int n, char* buf)
{
	assert(buf);
	int i = 0;
	while (n)
	{
		buf[i] = n % 10 + '0';
		n /= 10;
		++i;
	}
	
	int begin = 0, end = i - 1;
	while (begin < end)
	{
		char tmp = buf[end];
		buf[end] = buf[begin];
		buf[begin] = tmp;
		++begin;
		--end;
	}
	buf[i] = '\0';
	return buf;
}
int main()
{
	struct TelInfo info;
	strcpy(info._name, "sheena");
	strcpy(info._tel, "153****5645");
	info._age = 20;
	
	方法一:二进制读写法
	//FILE *fp = fopen("telinfo.c", "wb");
	//fwrite(&info, sizeof(info), 1, fp);
	//fclose(fp);

	//struct TelInfo other;
	//FILE *fp2 = fopen("telinfo.c", "rb");
	//fread(&other, sizeof(other), 1, fp2);
	//fclose(fp2);
	//printf("%s,%s,%d\n", other._name, other._tel, other._age);
	

	//方法二:文本读写法1
	FILE *fpout = fopen("input.c", "w");
	
	fputs(info._name, fpout);
	fputc('\n', fpout);
	
	fputs(info._tel, fpout);
	fputc('\n', fpout);
	
	char age_buf[12];
	my_itoa(info._age, age_buf);
	fputs(age_buf, fpout);
	fputc('\n', fpout);
	
	fclose(fpout);
	struct TelInfo other;
	FILE *fpin = fopen("input.c", "r");
	fscanf(fpin, "%s\n%s\n%d\n", other._name, other._tel, &other._age);
	fclose(fpin);
	printf("%s,%s,%d\n", other._name, other._tel, other._age);


	
	方法三:文本读写法2
	//FILE *fp = fopen("telinfo.c", "w");
	//fprintf(fp, "%s\n%s\n%d\n", info._name, info._tel, info._age);
	//fclose(fp);
	//
	//struct TelInfo other;
	//FILE *fpin = fopen("telinfo.c", "r");
	//fscanf(fpin, "%s\n%s\n%d\n", other._name, other._tel, &other._age);
	//fclose(fpin);
	//printf("%s,%s,%d\n", other._name, other._tel, other._age);
	
	return 0;
}
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值