[C语言]文件操作函数

本文主要学习**fopenfclosefgetcfgetsfputcfputsfwritefreadfeof**这几个文件操作函数。

以上函数,需要导入头文件 stdio.h

为什么要学习这些函数?肯定是因为我们需要存储我们的数据,使数据放入到硬盘中方便保存。

本文中梳理一些最常见的文件操作函数。

前言:文本文件和二进制文件

根据数据的组织形式,数据文件被称为文本文件或者二进制文件

数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件

如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件

一.文件的打开与关闭

文件指针

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

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE.

文件指针的创建

FILE* pf

定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件

二. fopenfclose

fopenfclose一般是成对出现的,有 fopen 就会有 fclose

fopen是打开文件的函数,fclose是关闭文件的函数

函数参数介绍

//打开文件
FILE * fopen ( const char * filename, const char * mode );

//关闭文件
fclose ( FILE * stream);

fopen的第一个参数,表示要打开的文件,如果在本目录下,直接书写文件名即可,如果不在本目录,就需要写出文件绝对路径。

fopen 的第二个参数表示对文件的操作形式,可看下图来学习。

java xlsx 文件打开宏_后端

fclose则是关闭我们打开的文件。

实例

在使用完fopen函数后,最好判断一下, fopen文件函数是否返回空指针NULL

int main()
{
	FILE* pr = fopen("data.txt", "r");//第一个参数是我要打开的文件名,第二个参数代表对文件的操作是“只读”
	if (NULL == pr)//判断pr是否文件是否打开成功
	{
		printf("open for reading : %s", strerror(errno));
		return 0;
	}

	FILE* pw = fopen("data2.txt", "w");//第一个参数是我要打开的文件名,第二个参数代表对文件的操作是“写入”
	if (NULL == pw)//判断文件是否打开成功
	{
		printf("open for writing : %s", strerror(errno));
		fclose(pr);//如果打开此文件失败,则关闭上一个文件。
		pr = NULL;
		return 0;
	}
    fclose(pr);//文件使用完成后,关闭文件
    pr = NULL;//并将文件指针置空
    fclose(pw);
    pw = NULL;
	return 0;
}

三. fputcfgetc

这两个文件函数在上个案列的代码演示中已经出现, fgetc 是读取文件中的字符, fputc是将字符输出到文件中。

//fgetc的函数参数
int fgetc( FILE *stream );//stream代表将要读取字符的文件

//fputc的函数参数
int fputc( int c, FILE *stream );// c 代表我们将要存入的字符,stream是我们存放 c 的文件。

实例

这是结合了上一个实例而成的。

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
	FILE* pr = fopen("data.txt", "r");//第一个参数是我要打开的文件名,第二个参数代表对文件的操作是“只读”
	if (NULL == pr)//判断pr是否文件是否打开成功
	{
		printf("open for reading : %s", strerror(errno));
		return 0;
	}

	FILE* pw = fopen("data2.txt", "w");//第一个参数是我要打开的文件名,第二个参数代表对文件的操作是“写入”
	if (NULL == pw)//判断文件是否打开成功
	{
		printf("open for writing : %s", strerror(errno));
		fclose(pr);//如果打开此文件失败,则关闭上一个文件。
		pr = NULL;
		return 0;
	}
	int ch = 0;
	while ((ch = fgetc(pr)) != EOF)//将“data.txt”文件的所有所有内容都写进“data2.txt”这个文件
	{
		fputc(ch, pw);
	}
	return 0;
}

四. fgetsfputs

fgets 是读取文件中数据的一行,相反,fputs则是输出一行到文件。

函数参数介绍

//fgets的函数参数
char *fgets( char *string, int n, FILE *stream );//第一个参数是我们接收文件中数据的字符串,第二个参数 n 表示我们要读取几个字符,不过字符数是 (n-1)个字符,第三个参数则是我们要读取的文件。

//fputs的函数参数
int fputs( const char *string, FILE *stream );//这个函数的参数实际和fgetc差不多,不过这里输出的是字符串到文件stream中,而不是一个字符。

实例

将数据输入到文件中,再次提醒,如果文件不在本目录下,需要加上绝对路径

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
	FILE* pf = fopen("data.txt", "w");
	if (NULL == pf)
	{
		printf("open for write : %s", strerror(errno));
		return 0;
	}
	fputs("hello world\n", pf);
	fputs("haha\n", pf);

	fclose(pf);
	pf = NULL;
	return 0;
}


java xlsx 文件打开宏_后端_02

java xlsx 文件打开宏_数据_03

读取文件

int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (NULL == pf)
	{
		printf("open for write : %s", strerror(errno));
		return 0;
	}
	char arr[2] = { 0 };//开辟两个空间来接收数据
	fgets(arr, 13, pf);// fgets只能读取(n-1)个字符,所以是13
	printf("%s", arr); 

	fgets(arr+1, 5 , pf);
	printf("%s", arr+1);


	fclose(pf);
	pf = NULL;
	return 0;
}

java xlsx 文件打开宏_后端_04

五.fwritefread

fwrite是二进制输出,也就是说,将内容以二进制的形式进行输出到文件中保存。

fread则是读取文件的以二进制保存的数据。

函数参数介绍

//fwrite函数参数
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );//第一个参数buffer表示我们要输出的数据的地址,第二参数size是我们要输出的数据大小,第三个参数是count是我们要输入的数据个数,第四个参数则是我们要将数据输入到的文件。

//fread函数参数
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );//第一个参数buffer表示我们要接收的数据的地址,第二参数size是我们要接收的数据大小,第三个参数是count是我们要接收的数据个数,第四个参数则是我们要将数据输入到的buffer的文件。

实例

fwrite 二进制输出

#include <stdio.h>
#include <errno.h>
#include <string.h>
struct Stu
{
	int age;
	char name[10];
	char id[20];
};
int main()
{
	struct Stu s[2] = { { 12, "zhangsan", "253534123" }, {13,"lisi","342342354"}};
	FILE* pr = fopen("date.txt", "wb");//wb表示:为了输出数据,打开一个二进制文件
	if (NULL == pr)
	{
		printf("open for writing : %s", strerror(errno));
	}
	fwrite(&s, sizeof(struct Stu), 2, pr);

	fclose(pr);
	pr = NULL;
	return 0;
}

运行后:

java xlsx 文件打开宏_c语言_05

java xlsx 文件打开宏_开发语言_06

使用 fread 读取date.txt中的数据

#include <stdio.h>
#include <errno.h>
#include <string.h>
struct Stu
{
	int age;
	char name[10];
	char id[20];
};
int main()
{
	struct Stu s[2] = { 0 };//开辟两个相同的结构体数组来接收数据
	FILE* pr = fopen("date.txt", "rb");
	if (NULL == pr)
	{
		printf("open for writing : %s", strerror(errno));
	}
	fread(s, sizeof(struct Stu), 2, pr);

	printf("%s %d %s\n", s[0].name, s[0].age, s[0].id);
	printf("%s %d %s\n", s[1].name, s[1].age, s[1].id);


	fclose(pr);
	pr = NULL;

	return 0;
}

java xlsx 文件打开宏_c语言_07

文件读取成功

六.feof

应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束

1.文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )

例如:

fgetc 判断是否为 EOF .

fgets 判断返回值是否为 NULL .

2.二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。

例如:

fread判断返回值是否小于实际要读的个数。

实例

文本文件的例子

#include <stdio.h>
#include <stdlib.h>
int main(void) {
    int c; // 注意:int,非char,要求处理EOF
    FILE* fp = fopen("test.txt", "r");
    if(!fp) {
        perror("File opening failed");
        return EXIT_FAILURE;
   }
 //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
    while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
   { 
       putchar(c);
   }
    //判断是什么原因结束的
    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");
    fclose(fp);
}

二进制文件的例子

#include <stdio.h>
enum { SIZE = 5 };
int main(void) {
    double a[SIZE] = {1.,2.,3.,4.,5.};
    FILE *fp = fopen("test.bin", "wb"); // 必须用二进制模式
    fwrite(a, sizeof *a, SIZE, fp); // 写 double 的数组
    fclose(fp);
    double b[SIZE];
    fp = fopen("test.bin","rb");
    size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 读 double 的数组
    if(ret_code == SIZE) {
        puts("Array read successfully, contents: ");
        for(int n = 0; n < SIZE; ++n) printf("%f ", b[n]);
        putchar('\n');
   } else { // error handling
       if (feof(fp))
          printf("Error reading test.bin: unexpected end of file\n");
       else if (ferror(fp)) {
           perror("Error reading test.bin");
       }
   }
    fclose(fp);
}