一、fgetc() 与 fputc()
#include <stdio.h>
int fgetc(FILE *stream);
int fputc(int c, FILE *stream);
- fgetc() 用于从文件流中读取下一个字符并推进文件的位置指示器,该函数将读取到的 unsigned char 类型转换为 int 类型并返回;如果文件结束或者遇到错误则返回 EOF。
- fputc() 用于将一个字符写入到指定的文件中并推进文件的位置指示器,如果写入成功,它会返回写入的字符,如果发生错误,则会返回 EOF。
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fpr;
FILE *fpw;
int ch;
/* 以只读模式打开本地 hello.txt 文件 */
if ((fpr = fopen("./hello.txt", "r")) == NULL) {
printf("文件打开失败!");
exit(EXIT_FAILURE);
}
/* 以写入模式打开 hello1.txt 文件,不存在就创建 */
if ((fpw = fopen("./hello1.txt", "w")) == NULL) {
printf("文件打开失败!");
exit(EXIT_FAILURE);
}
/* 循环从文件中读取一个字符 */
while ((ch = fgetc(fpr)) != EOF) {
/* 打印字符到标准输出 */
putchar(ch);
/* 打印字符到 fpw 文件流 */
fputc(ch, fpw);
}
/* 关闭文件 */
fclose(fpr);
fclose(fpw);
return 0;
}
二、fgets() 与 fputs()
#include <stdio.h>
/*
buff:用于存放读取到字符串的缓冲区
size:指定读取的字符数(包括最后自动添加的 '\0')
stream:待操作的文件流
*/
char *fgets(char *buff, int size, FILE *stream);
int fputs(const char *s, FILE *stream);
- fgets() 用于读取字符串到 buff 缓冲区,最多可以读取 size - 1 个字符,因为结尾处会自动添加一个字符串结束符 '\0'。当读取到换行符('\n')或文件结束符(EOF)时,表示结束读取('\n' 会被作为一个合法的字符读取)。如果函数调用成功,返回 buff 参数指向的地址。
- fputs() 用于将一个字符串写入到指定的文件中,表示字符串结尾的 '\0' 不会被一并写入。如果写入成功,它会返回一个非0值,如果发生错误,则会返回 EOF。
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fpr;
FILE *fpw;
char str[50];
/* 以只读模式打开本地 hello.txt 文件 */
if ((fpr = fopen("./hello.txt", "r")) == NULL) {
printf("文件打开失败!");
exit(EXIT_FAILURE);
}
/* 以写入模式打开 hello1.txt 文件,不存在就创建 */
if ((fpw = fopen("./hello1.txt", "w")) == NULL) {
printf("文件打开失败!");
exit(EXIT_FAILURE);
}
while (1) {
/* 读取字符串到缓冲区 */
fgets(str, 50, fpr);
/* 文件末尾指示器被设置时结束循环 */
if (feof(fpr)) {
break;
}
/* 打印字符串到标准输出 */
printf("%s", str);
/* 打印字符串到 fpw 文件流 */
fputs(str, fpw);
}
/* 关闭文件 */
fclose(fpr);
fclose(fpw);
return 0;
}
三、fscanf() 与 fprintf()
#include <stdio.h>
/*
format 格式化字符串,由格式化占位符和普通字符组成
... 附加参数
*/
int fscanf(FILE *stream, const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
- fscanf() 用于从指定文件中读取格式化字符串。如果函数调用成功,返回值是成功获取并填充到附加参数中的个数。如果函数调用失败,返回值小于附加参数的个数(甚至是 0)。如果读取到标准输入流的结尾处,则返回 EOF。
- fprintf() 用于打印格式化字符串到指定的文件。如果函数调用成功,返回值是实际打印的字符数(不包含表示字符串结束的 '\0');如果函数调用失败,返回值是一个负数。
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fpr;
FILE *fpw;
int year, month, day;
/* 以只读模式打开本地 hello.txt 文件 */
if ((fpr = fopen("./hello.txt", "r")) == NULL)
{
printf("文件打开失败!");
exit(EXIT_FAILURE);
}
/* 以写入模式打开 hello1.txt 文件,不存在就创建 */
if ((fpw = fopen("./hello1.txt", "w")) == NULL)
{
printf("文件打开失败!");
exit(EXIT_FAILURE);
}
int ch;
while ((ch = fscanf(fpr, "%d-%d-%d", &year, &month, &day)) != EOF)
{
/* 打印数据到标准输出 */
printf("%d-%d-%d\n", year, month, day);
/* 打印数据到 fpw 文件流*/
fprintf(fpw, "%d-%d-%d\n", year, month, day);
}
/* 关闭文件 */
fclose(fpr);
fclose(fpw);
return 0;
}
四、fread() 与 fwrite()
#include <stdio.h>
/*
ptr:指向存放数据的内存块指针,该内存块的尺寸最小应该是 size * nmemb 个字节
size:指定要读取/写入的每个元素的尺寸,最终尺寸等于 size * nmemb
nmemb:指定要读取/写入的元素个数,最终尺寸等于 size * nmemb
stream:待操作的文件流
*/
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
- fread() 用于从指定的文件中读取指定尺寸的数据。返回实际读取到的元素个数(nmemb);如果返回值比 nmemb 参数的值小,表示可能读取到文件末尾或者有错误发生(可以使用 feof 函数或 ferror 函数进一步判断)。
- fwrite() 用于将指定尺寸的数据写入到指定的文件中。返回实际写入到文件中的元素个数(nmemb);如果返回值与 nmemb 参数的值不同,则有错误发生。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Book
{
char name[50];
char author[50];
};
int main()
{
FILE *fpr;
FILE *fpw;
struct Book *book;
// 为结构体分配堆内存空间
book = (struct Book *)malloc(sizeof(struct Book));
if (book == NULL) {
printf("内存分配失败!\n");
exit(EXIT_FAILURE);
}
strcpy(book->name, "C语言备忘录");
strcpy(book->author, "liwy");
/* 以写入模式打开 hello1.txt 文件,不存在就创建 */
if ((fpw = fopen("./hello.txt", "w")) == NULL) {
printf("文件打开失败!");
exit(EXIT_FAILURE);
}
/* 将数据写入文件 */
fwrite(book, sizeof(struct Book), 1, fpw);
/* 关闭文件 */
fclose(fpw);
/* 以只读模式打开本地 hello.txt 文件 */
if ((fpr = fopen("./hello.txt", "r")) == NULL) {
printf("文件打开失败!");
exit(EXIT_FAILURE);
}
/* 读取指定尺寸的数据 */
fread(book, sizeof(struct Book), 1, fpr);
printf("书名:%s\n", book->name);
printf("作者:%s\n", book->author);
/* 关闭文件 */
fclose(fpr);
return 0;
}
五、IO缓冲区
对于数据流,有三种缓存模式:不缓存,按块缓存和按行缓存。如果输出流设置为不缓存,数据会直接写入目标文件或打印到屏幕上;如果设置为按块缓存,那么数据会先写入到缓存块中;如果设置为按行缓存,那么在接收到换行符('\n')之前,数据都是先缓存在缓冲区的。
1. fflush()
用于将缓冲区内的数据强制写入指定的文件中。
#include <stdio.h>
int fflush(FILE *stream);
如果函数调用成功,返回值是 0;如果函数调用失败,返回 EOF 并设置 errno 为指定的错误。
2. setvbuf()
用于指定一个数据流的缓存模式。
#include <stdio.h>
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
- stream :该参数是一个 FILE 对象的指针,指定一个打开的数据流
- buf :指定一个用户分配的缓冲区,如果该参数为 NULL,那么函数会自动分配一个指定尺寸的缓冲区
- mode :指定数据流的缓存模式:_IOFBF(按块缓存)、_IOLBF(按行缓存)、_IONBF(不缓存)
- size :指定缓冲区的尺寸(字节)
如果函数调用成功,返回值是 0;如果函数调用失败,返回值的是一个非 0 值。
#include <stdio.h>
#include <string.h>
int main(void)
{
char buff[1024];
memset(buff, '\0', sizeof(buff));
/* 按块缓冲,当缓冲区写满时才写入文件 */
setvbuf(stdout, buff, _IOFBF, 1024);
fprintf(stdout, "Hello C!\n");
/* 强制将缓冲区内容写入文件 */
fflush(stdout);
fprintf(stdout, "Hello liwy!\n");
// 阻塞, Hello liwy! 将不会输出
getchar();
return 0;
}