C语言常见文件操作
在C语言中主要通过标准的I/O函数来对文本文件进行操作。常见的文本操作函数包括
fopen()(打开) fclose()(关闭) fgetc()(读取字符) fputs()(写入字符) fprintf()(写入) fscanf()(读取)
1.打开文件
函数原型:
FILE * fopen(const char * path,const char * mode);
其中:
path :文件完整路径(如果没有指定路径,则默认为当前工作目录)
mode :为指定的打开模式
如果打开成功,fopen会返回一个结构指针地址,否则返回一个NULL。
FILE *fp;
fp = fopen("c:\\temp\\test.txt", "r")
使用fopen()函数打开的文件会先将文件复制到缓冲区。注意:所下达的读取或写入动作,都是针对缓冲区进行存取而不是磁盘,只有当使用fclose()函数关闭文件时,缓冲区中的数据才会写入磁盘。
1.1打开模式:
“r”:只能从文件中读数据,该文件必须先存在,否则打开失败
“w”:只能向文件写数据,若指定的文件不存在则创建它,如果存在则先删除它再重建一个新文件
“a”:向文件增加新数据(不删除原有数据),若文件不存在则会建立该文件
“r+”:可读/写数据,该文件必须先存在,否则打开失败
“w+”:可读/写数据,用该模式打开新建一个文件,先向该文件写数据,然后可读取该文件中的数据
“a+”:可读/写数据,原来的文件不被删去,位置指针移到文件末尾
打开二进制文件的模式与打开文本文件的含义是一样的,不同的是模式名称里面多一个字母’b’,以表示以二进制形式打开文件。
2.关闭文件:
函数原型:
int fclose( FILE *fp );
返回值:如果流成功关闭,fclose 返回 0,否则返回EOF(-1)。(如果流为NULL,而且程序可以继续执行,fclose设定error number给EINVAL,并返回EOF。)
注:在执行完文件的操作后,要进行“关闭文件”操作。虽然程序在结束前会自动关闭所有的打开文件,但文件打开过多会导致系统运行缓慢,这时就要自行手动关闭不再使用的文件,来提高系统整体的执行效率。
FILE *fp;
fp = fopen("c:\\temp\\test.txt", "r");
if(fp == NULL)
printf("fail to open the file! \n");
else
{
printf("The file is open! \n");
fclose(fp);
}
3.字符存取函数
函数原型为:
int fputc (char c, File *fp)
int fgetc(FILE *stream);
字符读取函数fgetc()可从文件数据流中一次读取一个字符,然后读取光标移动到下一个字符,并逐步将文件的内容读出。
如果字符读取成功,则返回所读取的字符,否则返回EOF(end of file)。EOF是表示数据结尾的常量,真值为-1。另外,要判断文件是否读取完毕,可利用feof()进行检查。未完返回0,已完返回非零值。
feof()函数原型为:
int feof(FILE *stream);
#include <stdio.h>
main()
{
FILE *fp;
fp = fopen("c:\\temp\\test.txt", "r");
if(fp != NULL)
{
while(!feof(fp))
printf("%c", fgetc(fp));
}
else
printf("fail to open! \n");
fclose(fp);
return 0;
}
若要将字符逐一写入文件,用fputc()函数。
示例为:
#include <stdio.h>
#include <conio.h>
main()
{
char filename[20], ch;
FILE *fp;
printf("Enter a filename: ");
scanf("%s", filename);
printf("Enter some characters to output to file: ");
if((fp = fopen(filename, "w")) == NULL)
printf("fail to open! \n");
else
{
while((ch = getche()) != '\015')
fputc(ch, fp);
}
fclose(fp);
return 0;
}
4.字符串存取函数
函数原型为:
int fputs(const char *, FILE *);
char * fgets(char *, int, FILE *);
fgets函数的作用是从指定文件读入一个字符串,如:fgets(str, n, fp);
参数n为要求得到的字符个数,但只从fp指向的文件输入n-1个字符,然后在最后加一个’\0’字符,因此得到的字符串共有n个字符,把它们放在字符数组str中。如果在读完n-1个字符之前遇到换行符或EOF,读入结束。
fputs函数的作用是向指定文件输出一个字符串,如:fputs(“Hey”, fp);
把字符串”Hey”输出到fp指向的文件。fputs函数的第一个参数可以是字符串常量、字符数组名或字符型指针。若输出成功,则返回0,否则返回EOF。
2.5 格式化存取函数
函数原型为:
int fprintf(FILE *, const char *, ...);
int fscanf(FILE *, const char *, ...);
它们与printf和scanf函数相仿,都是格式化读写函数。不同的是:fprintf和fscanf函数的读写对象不是终端(标准输入输出),而是磁盘文件。printf函数是将内容输出到终端(屏幕),因此,fprintf就是将内容输出到磁盘文件了。
#include <stdio.h>
void main()
{
FILE *fp;
int num = 10;
char name[10] = "Leeming";
char gender = 'M';
if((fp = fopen("info.txt", "w+")) == NULL)
printf("can't open the file! \n");
else
fprintf(fp, "%d, %s, %c", num, name, gender); //将数据格式化输出到文件info.txt中
fscanf(fp, "%d, %s, %c", &num, name, &gender); //从文件info.txt中格式化读取数据
printf("%d, %s, %c \n", num, name, gender); //格式化输出到屏幕
fclose(fp);
}
5. 指针重返函数
函数原型为:
void rewind(FILE *);
rewind函数的作用是使位置指针重返回文件的开头,属于文件的定位。
6.二进制文件操作
6.1 数据块存取函数
函数原型:
size_t fread(void *, size_t, size_t, FILE *);
size_t fwrite(const void *, size_t, size_t, FILE *);
当要求一次存取一组数据(如,一个数组、一个结构体变量的值),fread和fwrite函数可以解决该类问题。它们的调用形式一般为:
fread(buffer, size, count, fp);
fwrite(buffer, size, count, fp);
buffer:对于fread来说,指的是读入数据的存放地址;对于fwrite来说,是要输出数据的地址。
size:读写数据时,每笔数据的大小
count:读写数据的笔数
fp:文件指针
#include <stdio.h>
#define SIZE 3
typedef enum { MM, GG } Gender;
typedef struct
{
char name[10];
int age;
Gender gender;
} Person;
void write2file(Person emp[SIZE])
{
FILE *fp;
if((fp = fopen("emp.txt", "wb")) == NULL)
{
printf("cannot open file! \n");
return;
}
for(int i=0; i<SIZE; i++)
if(fwrite(&emp[i], sizeof(Person), 1, fp) != 1)
printf("file write error! \n");
fclose(fp);
}
void read_from_file(FILE *fp)
{
Person emp_out[SIZE];
if((fp = fopen("emp.txt", "rb")) == NULL)
{
printf("cannot open file! \n");
return;
}
printf("\n%d employee's information read: \n", SIZE);
for(int i=0; i<SIZE; i++)
{
if(fread(&emp_out[i], sizeof(Person), 1, fp) != 1)
if(feof(fp))
{
fclose(fp);
return;
}
printf("%-5s %4d %5d \n", emp_out[i].name, emp_out[i].age, emp_out[i].gender);
}
fclose(fp);
}
void main()
{
FILE *fp = NULL;
Person employee[SIZE];
printf("Enter %d employee's information: \n", SIZE);
for(int i=0; i<SIZE; i++)
scanf("%s %d %d", employee[i].name, &employee[i].age, &employee[i].gender);
write2file(employee);
read_from_file(fp);
}
7. 随机存取函数fseek()
函数原型:
int fseek(FILE *, long, int);
对流式文件可以进行顺序读写,也可以进行随机读写。关键在于控制文件的位置指针,如果位置指针是按字节位置顺序移动的,就是顺序读写。如果能将位置指针按需要移动到任意位置,就可以实现随机读写。所谓随机读写,是指读完上一个字符(字节)后,并不一定要读写其后续的字符(字节),而可以读写文件中任意位置上所需要的字符(字节)。该函数的调用形式为:
fseek(fp, offset, start);
start:起始点。用0、1、2代替。0代表文件开始,名字为SEEK_SET,1代表当前位置,名字为SEEK_CUR,2代表文件末尾,名字为SEEK_END。
fseek()函数一般用于二进制文件,因为文本文件要发生字符转换,计算位置时往往会发生混乱。
调用实例如:
fseek(fp, i*sizeof(Person), 0);