C语言中文件的读写
一.文件打开与关闭
文件指针
定义一个文件指针
FILE *fp;
fopen()
函数原型
FILE* fopen(char* filename, char* mode);
在通过 fopen
打开一个文件时,系统会先创建一个缓冲区,所有的读写操作其实就是针对缓冲区,而不是文件本身,如果打开失败会返回 NULL
。
fopen()的模式字符串有以下几种。
- r:读模式,只用来读取数据。如果文件不存在,返回 NULL 指针。
- w:写模式,只用来写入数据。如果文件存在,文件长度会被截为0,然后再写入;如果文件不存在,则创建该文件。
- a:写模式,只用来在文件尾部追加数据。如果文件不存在,则创建该文件。
- r+:读写模式。如果文件存在,指针指向文件开始处,可以在文件头部添加数据。如果文件不存在,返回 NULL 指针。
- w+:读写模式。如果文件存在,文件长度会被截为0,然后再写入数据。这种模式实际上读不到数据,反而会擦掉数据。如果文件不存在,则创建该文件。
- a+:读写模式。如果文件存在,指针指向文件结尾,可以在现有文件末尾添加内容。如果文件不存在,则创建该文件。
fopen()函数会为打开的文件创建一个缓冲区。读模式下,创建的是读缓存区;写模式下,创建的是写缓存区;读写模式下,会同时创建两个缓冲区。C 语言通过缓存区,以流的形式,向文件读写数据。
fclose()
函数原型
int fclose(FILE* stream);
自然,和前面动态创建内存一样,有始有终,打开了用完了还得记得关闭,它接受一个文件指针fp作为参数。如果成功关闭文件,fclose()函数返回整数0。
EOF
这是一个宏定义,它的值是 -1
, 只需记住它不是在文件末尾。
二. 顺序读写
1.putc(),fputc()
函数原型
int fputc(int char, FILE *stream);
int putc(int char, FILE *stream);
这两个函数都是用于从文件写入一个字符,功能都一样,只不过 petc
是通过宏定义实现的,性能会更好。特别注意,这个返回的是整形,如果写入失败返回 `EOF(-1) .
写如一个小写字母a在文件开头
FILE * fp;
// 打开一个文件
fp = fopen(file_name,"r+");
// 判断是否打开成功
if(fp == NULL){
printf("This file can't opne.\n");
}
if (putc(97,fp)==EOF){
printf("写入失败");
}
fclose(fp);
2.getc(),fgetc()
函数原型
int fgetc(FILE *stream)
int getc(FILE *stream);
这两个函数都是用于从文件中获取一个字符,功能都一样,只不过 getc
是通过宏定义实现的,性能会更好。特别注意,这个返回的是整形,如果读取到末尾会返回 EOF(-1)
.
循环读取整个文件
FILE * fp;
// 打开一个文件
fp = fopen(file_name,"r");
// 判断是否打开成功
if(fp == NULL){
printf("This file can't opne.\n");
}
int c;
while((c=getc(fp))!=EOF){
printf("%c",c);
}
fclose(fp);
getc
每次只会读取一个字节,所以文件中的中文会在显示的时候会出现乱码。3.fgets()
作用: fgets()用于从文件读取指定长度的字符串。
char* fgets(char* str, int STRLEN, File* fp);
假设文件中的内容为如下:
// test.txt
abcdefg
代码如下:
FILE *p = fopen("test.txt","r");
char buff[7];
fgets(buff,sizeof(buff),p);
printf("%s",buff) // abcdef
4.fputs()
作用: 向文件中写入一个字符串。
函数原型
int fputs(const char *str, FILE *stream);
参数
- str:要写入的字符串(以 \0 结尾)。
- stream:指向目标文件的指针。
返回值
- 成功时返回一个非负值。
- 失败时返回 EOF。
5.fprintf()
作用: 格式化文件写操作,将数据格式化输出到文件中去,并返回写入了多少个字符。
函数原型
int fprintf(FILE *stream, const char *format, ...);
fprintf()接受2个以上的参数。
- stream:文件指针。
- format:格式化字符串,和
scanf()
基本是一样的。 - ...:需要被格式化的变量或者字符串等等。
通过fprintf
我们可以向文件中格式化输入字符串。
FILE *p = fopen("data.txt","w");
fprintf(p,"Name: %s","aglorice");
// 等价于
fprintf(p,"Name: aglorice");
// 等价于
fputs("Name: aglorice",p);
特别注意fprintf()
函数返回的是写入了多少个字符,例如:
int count = fprintf(p,"Name: %s","aglorice");
printf("count = %d",count); // 14
6.fscanf()
作用: 格式化文件读操作
函数原型
int fscanf(FILE *stream, const char *format, ...);
fscanf()接受3个以上的参数。
- stream:文件指针。
- format:格式化字符串,和
scanf()
基本是一样的。 - ...:需要接受值得变量或者数组。
三.随机读写
1.fseek()
作用: 改变文件指针的位置,从而实现随机读写的操作。
函数原型
int fseek(FILE* stream, long int offset, int whence);
fseek()接受3个参数。
- stream:文件指针。
- offset:距离基准(第三个参数)的字节数。类型为 long int,可以为正值(向文件末尾移动)、负值(向文件开始处移动)或 0(保持不动)。
- whence:位置基准,用来确定计算起点。它的值是以下三个宏(定义在stdio.h):SEEK_SET(文件开始处)、SEEK_CUR(内部指针的当前位置)、SEEK_END(文件末尾)
2.rewind()
作用 : 回到文件起始位置。
函数原型
void rewind(file* stream);
相当于使用fseek(p,0L,SEEK_SET);
,只不过rewind
没有返回值。
3.fread()
作用:fread()函数用于一次性从文件读取较大的数据块,主要用途是将文件内容读入一个数组,适合读取二进制数据。
函数原型
size_t fread(
const void* ptr,
size_t size,
size_t nmemb,
FILE* fp
);
它接受四个参数。
- ptr:数组指针。
- size:每个数组成员的大小,单位字节。
- nmemb:数组成员的数量。
- fp:要写入的文件指针。
4.fwrite()
作用:功能是向指定的文件中写入若干数据块, 如成功执行则返回实际写入的数据 块数目。
函数原型
size_t fwrite(
const void* ptr,
size_t size,
size_t nmemb,
FILE* fp
);
它接受四个参数。
- ptr:数组指针。
- size:每个数组成员的大小,单位字节。
- nmemb:数组成员的数量。
- fp:要写入的文件指针。
5.ftell()
作用: 返回当前文件指针指向的位置。
函数原型
long ftell(FILE *fp);
它接受一个参数。
- fp:要写入的文件指针。
返回值
- 返回文件指针指向的位置(字节为单位).
- 出现错误返回
-1L
.
ftell()
返回的是一个long int
。借助fseek()
我们可以读取文件的整个大小。
FILE *p = fopen("data.txt","r");
fseek(p,0L,SEEK_END);
printf("当前文件大小为 : %ld",ftell(p));