上期回顾: 【C语言基础】:文件操作详解(前篇:准备知识)
一、文件的顺序读写
1.1 顺序函数读写函数介绍
1.2 fgetc函数和fputc函数
fputc函数原型:
int fputc ( int character, FILE * stream );
将字符写入流
将一个字符写入流并推进位置指示器。
字符被写入流的内部位置指示器所指示的位置,然后自动向前移动一个。
参数说明:
character: 要写入的字符,以整数形式表示。
stream :指向要写入的文件的文件指针。
函数返回值:
如果成功写入字符,则返回写入的字符,如果发生错误,则返回 EOF。
【示例1】:
#include<stdio.h> int main() { // 打开文件 FILE* pf = fopen("test1.txt", "w"); if (pf == NULL) { perror("fopen"); return 1; } // 写文件 fputc('a', pf); fputc('b', pf); fputc('c', pf); // 关闭文件 fclose(pf); pf = NULL; return 0; }
【示例2】:
#include<stdio.h> int main() { // 打开文件 FILE* pf = fopen("test1.txt", "w"); if (pf == NULL) { perror("fopen"); return 1; } // 写文件 char ch = 0; for (ch = 'A'; ch <= 'Z'; ch++) { fputc(ch, pf); } // 关闭文件 fclose(pf); pf = NULL; return 0; }
fgetc函数原型:
int fgetc ( FILE * stream );
从流中获取字符
返回指定流的内部文件位置指示符当前指向的字符。然后将内部文件位置指示符推进到下一个字符。
如果流在被调用时位于文件的末尾,则该函数返回EOF并为流设置文件结束指示器(feof)。
如果发生读错误,该函数返回EOF并设置流的错误指示器(error)。
fgetc和fgetc是等价的,除了getc可以在某些库中作为宏实现。
参数说明:
stream: 指向要读取的文件的文件指针。
函数返回值:
如果成功读取一个字符,则返回读取的字符,如果已到达文件末尾或发生错误,则返回 EOF。
返回值是整形的原因:
- 读取成功,返回该字符的ASCII值。
- 读到文件末尾或则读取失败,返回EOF(-1)。
【示例1】:
#include<stdio.h> int main() { // 打开文件 FILE* pf = fopen("test1.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } // 读文件 int ch = fgetc(pf); printf("%c", ch); ch = fgetc(pf); printf("%c", ch); ch = fgetc(pf); printf("%c", ch); // 关闭文件 fclose(pf); pf = NULL; return 0; }
【示例2】:
#include<stdio.h> int main() { // 打开文件 FILE* pf = fopen("test1.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } // 读文件 char ch = 0; while ((ch = fgetc(pf)) != EOF) { printf("%c", ch); } // 关闭文件 fclose(pf); pf = NULL; return 0; }
1.3 fputs函数和fgets函数
fputs函数原型:
int fputs ( const char * str, FILE * stream );
将字符串写入流
将由str指向的C字符串写入流。
函数从指定的地址(str)开始复制,直到到达结束的空字符(‘\0’)。这个终止的空字符不会复制到流中。
注意,fputs与puts的不同之处不仅在于可以指定目标流,而且fputs不会写入额外的字符,而puts会自动在末尾附加一个换行符。
参数说明:
str: 要写入的字符串,以 const char * 类型表示。
stream: 指向要写入的文件的文件指针。
函数返回值:
如果成功写入字符串,则返回非负值(通常为 0),如果发生错误,则返回 EOF。
【示例】:
#include<stdio.h> int main() { // 打开文件 FILE* pf = fopen("test1.txt", "w"); if (pf == NULL) { perror("fopen"); return 1; } // 写文件 fputs("hello", pf); fputs(" world", pf); // 关闭文件 fclose(pf); pf = NULL; return 0; }
fgets函数原型:
char * fgets ( char * str, int num, FILE * stream );
从流中获取字符串
从流中读取字符,并将其作为C字符串存储到str中,直到读取(num-1)个字符,或者到达换行符或文件结束符,以先发生的为准。
换行符使fgets停止读取,但它被函数认为是一个有效字符,并包含在复制到str的字符串中。
在复制到str的字符之后,将自动追加一个终止null字符。
请注意,fgets与gets有很大的不同:fgets不仅接受流参数,而且允许指定str的最大长度,并在字符串中包含任何结束换行符。
参数说明:
str: 一个指向字符数组的指针,用于存储读取的字符。
num: 要读取的最大字符数(包括空字符),通常是 str 缓冲区的大小。
stream: 指向要读取的文件的文件指针。
函数返回值:
如果成功读取一行字符,则返回 str 参数的值;如果到达文件末尾或发生错误,则返回 NULL。
【示例】:
#include<stdio.h> int main() { // 打开文件 FILE* pf = fopen("test1.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } // 读文件 char arr[10] = { 0 }; fgets(arr, 10, pf); printf("%s\n", arr); // 关闭文件 fclose(pf); pf = NULL; return 0; }
注意:要求读10个字符,结果却只读9个,因为\0也会算进去。
1.4 fprintf函数和fscanf函数
fprintf函数原型:
int fprintf ( FILE * stream, const char * format, ... );
将格式化的数据写入流
将由format指向的C字符串写入流。如果format包含格式说明符(以%开头的子序列),则格式化format之后的其他参数并将其插入到结果字符串中,以替换它们各自的说明符。
在format形参之后,函数期望至少与format指定的一样多的附加参数。
参数说明如下:
stream:指向文件的指针,它指定了数据将要被写入的文件。
format:一个格式化字符串,其中包含了要写入的数据以及格式化说明符。
…:可变数量的参数,根据 format 字符串中的格式化说明符指定了要写入的数据。
fprintf 函数的返回值是一个 int 类型,表示成功写入的字符数,如果发生错误则返回一个负数。
【示例】:
#include<stdio.h> struct S { char name[20]; int age; float score; }; int main() { struct S s = { "张三", 19, 89.5 }; // 打开文件 FILE* pf = fopen("test1.txt", "w"); if (pf == NULL) { perror("fopen"); return 1; } // 写文件 fprintf(pf, "%s %d %f", s.name, s.age, s.score); // 关闭文件 fclose(pf); pf = NULL; return 0; }
fscanf函数原型:
int fscanf ( FILE * stream, const char * format, ... );
从流中读取格式化的数据
从流中读取数据,并根据参数格式将其存储到附加参数所指向的位置。
额外的参数应该指向已经分配的对象,其类型由格式字符串中相应的格式说明符指定。
参数说明如下:
stream:指向文件的指针,它指定了从中读取数据的文件。
format:一个格式化字符串,其中包含了要读取的数据的格式化说明符。
…:可变数量的参数,根据 format 字符串中的格式化说明符指定了要读取的数据。
fscanf 函数的返回值是一个 int 类型,表示成功读取并匹配的数据项的数量。如果到达文件结束或发生读取错误,则返回 EOF (-1)。
【示例】:
#include<stdio.h> struct S { char name[20]; int age; float score; }; int main() { struct S s = { "张三", 19, 89.5f }; // 打开文件 FILE* pf = fopen("test1.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } // 读文件 fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.score)); // 打印到屏幕上 printf("%s %d %f\n", s.name, s.age, s.score); // 关闭文件 fclose(pf); pf = NULL; return 0; }
1.5 fwrite函数和fread函数
fwrite函数原型:
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
将数据块写入流
将由count元素组成的数组(每个元素的大小为size字节)从ptr所指向的内存块写入流中的当前位置。
流的位置指示器按写入的总字节数前进。
在内部,该函数将ptr指向的块解释为unsigned char类型的(size*count)元素数组,并将它们顺序写入流,就像对每个字节调用fputc一样。
参数说明如下:
ptr:指向要写入的数据块的指针。
size:每个数据项的大小(以字节为单位)。
count:要写入的数据项的数量。
stream:指向文件的指针,它指定了数据将要被写入的文件。
fwrite 函数的返回值是一个 size_t 类型,表示成功写入的数据项的数量。如果发生错误,则返回一个小于 count 的值。
【示例】:
#include<stdio.h> int main() { int arr[] = { 1,2,3,4,5 }; // 打开文件 FILE* pf = fopen("test1.txt", "wb"); if (pf == NULL) { perror("fopen"); return 1; } // 写文件 int sz = sizeof(arr) / sizeof(arr[0]); fwrite(arr, sizeof(arr[0]), sz, pf); // 以二进制的形式写入 // 关闭文件 fclose(pf); pf = NULL; return 0; }
fread函数原型:
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
从流中读取一个由count元素组成的数组,每个元素的大小为size字节,并将它们存储在ptr指定的内存块中。
流的位置指示器按读取的总字节数前进。
如果成功读取的总字节数为(size*count)。
参数说明如下:
ptr:指向存储读取数据的缓冲区的指针。
size:每个数据项的大小(以字节为单位)。
count:要读取的数据项的数量。
stream:指向文件的指针,它指定了从中读取数据的文件。
fread 函数的返回值是一个 size_t 类型,表示成功读取的数据项的数量。如果到达文件末尾或发生读取错误,则返回一个小于 count 的值。
【示例】:
#include<stdio.h> int main() { int arr[5] = { 0 }; // 打开文件 FILE* pf = fopen("test1.txt", "rb"); if (pf == NULL) { perror("fopen"); return 1; } // 读文件 fread(arr, sizeof(arr[0]), 5, pf); for (int i = 0; i < 5; i++) { printf("%d ", arr[i]); } // 关闭文件 fclose(pf); pf = NULL; return 0; }
上面说的适用于所有输入流一般指适用于标准输入流和其他输入流(如文件输入流);所有输出流一般指适用于标准输出流和其他输出流(如文件输出流)
【C语言基础】:文件操作详解(后篇)-2