6.文件的操作

FILE指针

C语言,每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及 文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE. 例如,VS2008编译环境提供的stdio.h 头文件中有以下的文件类型申明:

struct _iobuf{
    char*_ptr; 
    int _cnt; 
    char *_base; 
    int _flag;  
    int _file; 
    int _charbuf; 
    int _bufsiz; 
    char*_tmpfname;
    }; 
typedef struct _iobuf FILE;

不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。 每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关 心细节。 一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。


打开关闭文件

打开文件
fopen函数原型:
FILE *fopen(const char *path, const char *mode);

参数:第一个参数是文件路径,第二个参数是打开文件的方式,类型均为字符串

使用示例
pFile = fopen("myfile.txt", "w");
#include <stdio.h>
int main(){
	FILE* pFile;
	pFile = fopen("myfile.txt", "w");
	if (pFile != NULL)	{
		fputs("fopen example", pFile);
		fclose(pFile);
	}
	return 0;
}

若是没有这个文件,便会创建一个文件

第二个参数选择
文件使用方式含义如果指定文件不存在
“r”(读)打开文件用于读出错
“w”(写)将文件截断为零长度或创建文本文件以进行写入建立一个新的文件
“rt”(只读) 1打开一个文本文件,只允许读数据出错
“wt”(只写)只写打开或建立一个文本文件,只允许写数据建立一个新文件
“a”(追加)向文本文件尾追加数据出错
“rb”(追加)打开一个二进制文件读出错
“wb”(只写)打开一个二进制文件写建立一个新的文件
“ab”(追加)向一个二进制文件尾添加数据出错
“r+”(读写)为了读和写,打开一个文本文件出错
“w+”(读写)为了读和写,建立一个新的文件建立一个新文件
“a+”(读写)打开一个文件,在文件尾进行读写建立一个新的文件
“rb+”(读写) 2为了读和写打开一个二进制文件出错
“wb+”(读写)为了读和写,新建一个新的二进制文件建立一个新的文件
“ab+”(读写)打开一个二进制文件,在文件尾进行读和写建立一个新的文件

关闭文件
fclose函数原型:
int fclose(FILE *stream);

参数:唯一的一个参数是需要关闭的文件指针


文件读写

顺序读写
功能函数名适用于
字符输出函数fputc所有输出流
字符输入函数fgetc所有输入流
文本行输出函数fputs所有输出流
文本行输入函数fgets所有输入流
格式化输出函数fprintf所有输出流
格式化输入函数fscanf所有输入流
二进制输出fwrite文件
二进制输入fread文件
fputc函数原型:
int fputc( int c, FILE *stream );

参数:第一个参数是要写入的字符,第二个参数是要写入的文件流

使用示例
    FILE* pFile = fopen("fputc.txt", "w");
	char* str = "This is a test of fputc!!\n";
	char* p_str = str;
	while ((*p_str != '\0') && fputc(*(p_str++), stdout) != EOF);
	p_str = str;
	while ((*p_str != '\0') && fputc(*(p_str++), pFile) != EOF);

FILE指针其实就是文件流,也是流的一种,与标准输入输出流使用起来差不多

fgetc函数原型:
int fgetc( FILE *stream );

参数:stream是要读取的目的流

使用示例
    //先使用fputs写一个文本文件
	FILE* pFile = fopen("fgetc.txt", "w");
	char* str = "This is a test of fgetc!!\n";
	fputs("Hello world from fgetc.\n", pFile);
	fclose(pFile);
	//使用fgetc读取这个文本文件的内容
	pFile = fopen("fgetc.txt", "r");
	while(feof(pFile) == 0){
		char ch = fgetc(pFile);
		fputc((char)ch, stdout);
	}
	fclose(pFile);
    

fputs函数原型:
int fputs( const char *string, FILE *stream );

参数:第一个是要写入文件的字符串,第二个参数是输出流

使用示例
    FILE* pFile = fopen("fputs.txt", "w");
	char* str = "This is a test of fputs!!\n";
    fputs(str, pFile);

fgets函数原型:
char *fgets(char *restrict s, int n, FILE *restrict stream);

参数:从stream流中读取最大n个字符量的字符串保存到s字符中

使用示例
//先使用fputs写入一个文本文件
	FILE* pFile = fopen("fgets.txt", "w");
	char* str = "This is a test of fgets!!\n";
	fputs(str, pFile);
	fclose(pFile);
	//再使用fgets读
	char line[1000];
	if ((pFile = fopen("fgets.txt", "r")) != NULL)
	{
		if (fgets(line, 1000, pFile) == NULL)
			printf("fgets error\n");
		else
			printf("%s", line);
		fclose(pFile);
	}

fprintf函数原型:
int fprintf( FILE *stream, const char *format [, argument ]...);

参数:stream要输出的流,format是格式控制字符串,argument是多个变量

使用示例
    int    i = 10;
	double fp = 1.5;
	char   s[] = "this is a string";
	char   c = '\n';

	FILE* stream = fopen("fprintf.out", "w");
	fprintf(stream, "%s%c", s, c);
	fprintf(stream, "%d\n", i);
	fprintf(stream, "%f\n", fp);
	fclose(stream);
	system("type fprintf.out");

与标准输出的printf区别在于多了第一个指定输出的流参数,out后缀文件内容直接可以使用system打印到标准输出流


fscanf函数原型:
int fscanf( FILE *stream, const char *format [, argument ]... );

参数:从stream流按format格式解析数据依次存储到arguments中

使用示例
    //先使用fprintf向文件输入
    int    i = 10;
	double fp = 1.5;
	char   s[] = "string";
	char   c = 'U';

	FILE* stream = fopen("fscanf.out", "w");
	fprintf(stream, "%s %c", s, c);
	//s字符串需要scanf读取的话,没有空格和换行的字符串请用空格与后面的变量隔开,如果字符串含空格,建议将字符串作为一整行用fgets读取
	fprintf(stream, "%d\n", i);
	fprintf(stream, "%f\n", fp);
	fclose(stream);
	
	//使用fscanf读取文件数据
	stream = fopen("fscanf.out", "r");
	fscanf(stream, "%s", &s);
	fscanf(stream, "%c", &c); //捕捉空格
	fscanf(stream, "%c", &c);
	printf("%s %c\n", s, c);
	fscanf(stream, "%d", &i);
	fscanf(stream, "%f", &fp);
	printf("%d\n%f\n", i, fp);
	fclose(stream);

fwrite函数原型:
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );

参数:buffer是将要被写的数据,size是元素字节大小,count是元素个数,stream是要写的目的流

使用示例
    FILE* stream = fopen("fwrite.out", "w+t");
	char list[] = "abcdefghijklmnopqrstuvwxyz";
	if (stream  != NULL)	{
		char numwritten = fwrite(list, sizeof(char), strlen(list), stream);
		printf("Wrote %d items\n", numwritten);
		fclose(stream);
	}
	system("type fread.out");

fwrite可以写入count个字符、整形或者size大小的字符串


fread函数原型:
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );

参数:buffer是读取的数据存储区,size是单个元素大小,count是

使用示例
    //读取上面fwrite保存的fwrite.out文件
    if ((stream = fopen("fwrite.out", "r+t")) != NULL)
	{
		char numread = fread(list, sizeof(char), 26, stream);
		printf("Number of items read = %d\n", numread);
		printf("Contents of buffer = %.26s\n", list);
		fclose(stream);
	}
	else
		printf("File could not be opened\n");

随机读写

文件指针跳转任意位置
fseek函数原型
int fseek(FILE * stream, long int offset, int origin);

参数:stream是所操作的流,offset是偏移量,origin是基准偏移起始位置

基准偏移基准位置
SEEK_SET文件起始
SEEK_CUR文件指针所指向的当前位置
SEEK_END文件结尾
使用示例
    FILE* pFile = fopen("example.txt", "wb");
	fputs("This is an apple.", pFile);
	fseek(pFile, 9, SEEK_SET);
	fputs(" sam", pFile);
	fclose(pFile);
	system("type example.txt");

返回文件指针相对于起始位置的偏移量
ftell函数原型
long ftell( FILE *stream );

参数:stream是得到偏移量的目标流

使用示例
    FILE* stream = fopen("ftell.c", "w+");
	srand(time(NULL));
	int charNumber = 150;
	while (charNumber--)
		fputc(rand() % 57 + 65, stream);

	//得到当前的偏移量
	long position;
	position = ftell(stream);
	printf("Position after trying to read 100 bytes: %ld\n",
		position);
	fclose(stream);


文件指针的位置回到文件的起始位置
rewind函数原型
void rewind ( FILE * stream );

参数:stream是将文件指针指向文件起始的目标流

使用示例
    //写一个文件用于测试
    char list[100];
	FILE* stream = fopen("rewind.c", "w");
	srand(time(NULL));
	int charNumber = 150;
	while (charNumber--)
		fputc(rand() % 57 + 65, stream);
	fclose(stream);
	stream = fopen("rewind.c", "r");
	
	//读
	fread(list, sizeof(char), 100, stream);
	char position = ftell(stream);
	printf("Position after read: %ld\n",
		position);
		
	//文件指针回到文件首
	rewind(stream);
	position = ftell(stream);
	printf("Position after back to start: %ld\n",
		position);
	fclose(stream);

刚写完不关闭文件流读取文件指纹偏移量是负数

FILE* stream = fopen("rewind.c", "w");
	srand(time(NULL));
	int charNumber = 150;
	while (charNumber--)
		fputc(rand() % 57 + 65, stream);
	char position = ftell(stream);
	printf("Position after write: %ld\n", position);

文件结束判定
feof函数原型
int feof( FILE *stream );

参数:判断文件指针是否到达文件结尾的目标流

fgetc、fgetc、fread、fprintf当读到文件结尾时就会返回EOF

使用示例
    //创建feof.c
	FILE* stream = fopen("feof.c", "w");
	srand(time(NULL));
	int charNumber = 80;
	while (charNumber--)
		fputc(rand() % 57 + 65, stream);
	fclose(stream);

	//读feof.c
	int  count, total = 0;
	char buffer[100];
	if ((stream = fopen("feof.c", "r")) == NULL)
		exit(1);


	//结合feof就可以循环读到文件结尾
	/* Cycle until end of file reached: */
	while (!feof(stream))
	{
		/* Attempt to read in 10 bytes: */
		count = fread(buffer, sizeof(char), 100, stream);
		if (ferror(stream)) {
			perror("Read error");
			break;
		}

		/* Total up actual bytes read */
		total += count;
	}
	printf("Number of bytes read = %d\n", total);
	fclose(stream);

读二进制文件示例

#include <stdio.h>
enum { SIZE = 5 };
int main(void)
{
	double a[SIZE] = { 1.0,2.0,3.0,4.0,5.0 };
	double b = 0.0;
	size_t ret_code = 0;
	FILE* fp = fopen("test.bin", "wb"); // 必须用二进制模式
	fwrite(a, sizeof(*a), SIZE, fp); // 写 double 的数组
	fclose(fp);
	fp = fopen("test.bin", "rb");
	// 读 double 的数组
	while ((ret_code = fread(&b, sizeof(double), 1, fp)) >= 1)
	{
		printf("%lf\n", b);
	}
	if (feof(fp))
		printf("Error reading test.bin: unexpected end of file\n");
	else if (ferror(fp)) {
		perror("Error reading test.bin");
	}
	fclose(fp);
	fp = NULL;
}


  1. 等价于r+t ↩︎

  2. 等价于r+b ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值