参考 https://fishc.com.cn/forum.php?mod=forumdisplay&fid=329&filter=typeid&typeid=583
打开文件
fopen 打开一个文件并返回文件指针。
#include <stdio.h>
...
FILE *fopen(const char *path, const char *mode);
参数解析:
参数 | 含义 |
---|---|
path | 该参数是一个 C 语言字符串,指定了待打开的文件路径和文件名(见备注) |
mode | 1. 该参数是一个 C 语言字符串,指定了文件的打开模式 2. 下面列举了所有可使用的打开模式: |
模式 | 描述 |
"r" | 1. 以只读的模式打开一个文本文件,从文件头开始读取 2. 该文本文件必须存在 |
"w" | 1. 以只写的模式打开一个文本文件,从文件头开始写入 2.如果文件不存在则创建一个新的文件 3. 如果文件已存在则将文件的长度截断为 0(重新写入的内容将覆盖原有的所有内容) |
"a" | 1. 以追加的模式打开一个文本文件,从文件末尾追加内容 2. 如果文件不存在则创建一个新的文件 |
"r+" | 1. 以读和写的模式打开一个文本文件,从文件头开始读取和写入 2. 该文件必须存在 3. 该模式不会将文件的长度截断为 0(只覆盖重新写入的内容,原有的内容保留) |
"w+" | 1. 以读和写的模式打开一个文本文件,从文件头开始读取和写入 2. 如果文件不存在则创建一个新的文件 3. 如果文件已存在则将文件的长度截断为 0(重新写入的内容将覆盖原有的所有内容) |
"a+" | 1. 以读和追加的模式打开一个文本文件 2. 如果文件不存在则创建一个新的文件 3. 读取是从文件头开始,而写入则是在文件末尾追加 |
"b" | 1. 与上面 6 中模式均可结合("rb", "wb", "ab", "r+b", "w+b", "a+b") 2. 其描述的含义一样,只不过操作的对象是二进制文件(见备注) |
返回值:
如果文件打开成功,则返回一个指向 FILE 结构的文件指针;
如果文件打开失败,则返回 NULL 并设置 errno 为指定的错误。
备注:
path 参数可以是相对路径(../fishc.txt)也可以是绝对路径(/home/FishC/fishc.txt),如果只给出文件名而不包含路径,则表示该文件在当前文件夹中
从本质上来说,文本文件也是属于二进制文件的,只不过它存放的是相应的字符编码值。
打开方式要区分文本模式和二进制模式的原因,主要是因为换行符的问题。C 语言用 \n 表示换行符,Unix 系统用 \n,Windows 系统用 \r\n,Mac 系统则用 \r。如果在 Windows 系统上以文本模式打开一个文件,从文件读到的 \r\n 将会自动转换成 \n,而写入文件则将 \n 替换为 \r\n。但如果以二进制模式打开则不会做这样的转换。Unix 系统的换行符跟 C 语言是一致的,所以不管以文本模式打开还是二进制模式打开,结果都是一样的。
关闭文件
fclose 函数用于关闭先前由 fopen 函数打开的文件。
fclose 函数会将缓冲区内的数据写入文件中,并释放系统所提供的文件资源。
#include <stdio.h>
...
int fclose(FILE *fp);
返回值:
如果文件关闭成功,返回值是 0;
如果文件关闭失败,返回值是 EOF,并设置 errno 为指定的错误。
写入文件
- fputc
- 函数用于将一个字符写入到指定的文件中并推进文件的位置指示器(用来指示接下来要读写的下一个字符的位置)。
-
fputc
函数和putc
函数两个的功能和描述基本上是一模一样的,它们的区别主要在于实现上:fputc
是一个函数;而putc
则是一个宏的实现
#include <stdio.h>
...
int fputc(int c, FILE *stream);
- fputs
- fputs 函数用于将一个字符串写入到指定的文件中,表示字符串结尾的 '\0' 不会被一并写入。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
int ch;
if ((fp = fopen("file.txt", "w")) == NULL)
{
printf("打开文件失败!\n");
exit(EXIT_FAILURE);
}
fputs("I love FishC.com!\n", fp);
fclose(fp);
return 0;
}
- fwrite
- fwrite 函数用于将指定尺寸的数据写入到指定的文件中。
#include <stdio.h>
...
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Date
{
int year;
int month;
int day;
};
struct Book
{
char name[40];
char author[40];
char publisher[40];
struct Date date;
};
int main(void)
{
FILE *fp;
struct Book *book_for_write, *book_for_read;
// 为结构体分配堆内存空间
book_for_write = (struct Book *)malloc(sizeof (struct Book));
book_for_read = (struct Book *)malloc(sizeof (struct Book));
if (book_for_write == NULL || book_for_read == NULL)
{
printf("内存分配失败!\n");
exit(EXIT_SUCCESS);
}
// 填充结构体数据
strcpy(book_for_write->name, "《带你学C带你飞》");
strcpy(book_for_write->author, "小甲鱼");
strcpy(book_for_write->publisher, "清华大学出版社");
book_for_write->date.year = 2017;
book_for_write->date.month = 11;
book_for_write->date.day = 11;
if ((fp = fopen("file.txt", "w")) == NULL)
{
printf("打开文件失败!\n");
exit(EXIT_SUCCESS);
}
// 将整个结构体写入文件中
fwrite(book_for_write, sizeof(struct Book), 1, fp);
// 写入完成,关闭保存文件
fclose(fp);
// 重新打开文件,检测是否成功写入数据
if ((fp = fopen("file.txt", "r")) == NULL)
{
printf("打开文件失败!\n");
exit(EXIT_FAILURE);
}
// 在文件中读取结构体并打印到屏幕上
fread(book_for_read, sizeof(struct Book), 1, fp);
printf("书名:%s\n", book_for_read->name);
printf("作者:%s\n", book_for_read->author);
printf("出版社:%s\n", book_for_read->publisher);
printf("出版日期:%d-%d-%d\n", book_for_read->date.year, book_for_read->date.month, book_for_read->date.day);
fclose(fp);
return 0;
}
读取文件
- fgetc
- fgetc 函数用于从文件流中读取下一个字符并推进文件的位置指示器(用来指示接下来要读写的下一个字符的位置)。
- fgetc 函数和 getc 函数两个的功能和描述基本上是一模一样的,它们的区别主要在于实现上:fgetc 是一个函数;而 getc 则是一个宏的实现
#include <stdio.h>
...
int fgetc(FILE *stream);
- fgets
- fgets 函数用于从指定文件中读取字符串。
- fgets 函数最多可以读取 size - 1 个字符,因为结尾处会自动添加一个字符串结束符 '\0'。当读取到换行符('\n')或文件结束符(EOF)时,表示结束读取('\n' 会被作为一个合法的字符读取)。
#include <stdio.h>
...
char *fgets(char *s, int size, FILE *stream);
- fread
- fread 函数用于从指定的文件中读取指定尺寸的数据。
#include <stdio.h>
...
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
缓冲区
fflush 函数用于将缓冲区内的数据强制写入指定的文件中。
#include <stdio.h>
...
int fflush(FILE *stream);
返回值:
如果函数调用成功,返回值是 0;
如果函数调用失败,返回 EOF 并设置 errno 为指定的错误。
#include <stdio.h>
#include <string.h>
int main(void)
{
char buff[1024];
memset(buff, '\0', sizeof(buff));
// 指定 buff 为缓冲区,_IOFBF 表示当缓冲区已满时才写入 stdout
setvbuf(stdout, buff, _IOFBF, 1024);
fprintf(stdout, "This is bbs.fishc.com\n");
fprintf(stdout, "This output will go into buff\n");
// fflush强制将上面缓存中的内容写入stdout
fflush(stdout);
fprintf(stdout, "this will appear when progream\n");
fprintf(stdout, "will come after sleeping 5 seconds\n");
sleep(5);
return 0;
}