01. 文件打开和关闭
#include <stdio.h>
FILE * fopen(const char * filename, const char * mode);
功能:打开文件
参数:
参1:需要打开的文件名,根据需要加上路径
参2:打开文件的模式设置
返回值:
成功:文件指针
失败:NULL
打开模式 | 含义 |
---|---|
r或rb | 以只读方式打开文件。文件不存在,则报错 |
w或wb | 以写方式打开文件。文件存在,清空文件并打开,文件不存在,则创建该文件 |
a或ab | 以追加的方式打开文件,在末尾添加内容。文件不存在,创建文件 |
r+或rb+ | 以读写方式打开文件,文件不存在,则报错 |
w+或wb+ | 以读写方式打开文件,文件存在,清空文件并打开,文件不存在,则创建该文件 |
a+或ab+ | 以追加的方式打开文件,在末尾添加内容。文件不存在,创建文件 |
注意:
- b是二进制模式的意思,b只是在Windows有效,在Linux用r和rb的结果是一样的
- Unix和Linux下所有的文本文件行都是\n结尾,而Windows所有的文本文件行都是\r\n结尾
- 在Windows平台下,以“文本”方式打开文件,不加b:
- 当读取文件的时候,系统会将所有的 “\r\n” 转换成 “\n”
- 当写入文件的时候,系统会将 “\n” 转换成 “\r\n” 写入
- 以"二进制"方式打开文件,则读\写都不会进行这样的转换
- 在Unix/Linux平台下,“文本”与“二进制”模式没有区别,“\r\n” 作为两个字符原样输入输出
#include <stdio.h>
int fclose(FILE * stream);
功能:关闭先前fopen()打开的文件。此动作让缓冲区的数据写入文件中,并释放系统所提供的文件资源。
参数:文件指针
返回值:
成功:0
失败:-1
#include <stdio.h>
int main()
{
FILE* fp = NULL;
//打开文件
fp = fopen("./test","w"); //以w写方式打开
if(fp == NULL)
{
perror("open err"); //是标准出错打印函数,能打印调用库函数出错原因
return -1;
}
//关闭文件
fclose(fp);
return 0;
}
02. 文件的读写操作
按照字符读写文件fgetc、fputc
fputc()函数
#include <stdio.h>
int fputc(int ch, FILE * stream);
功能:将ch转换为unsigned char后写入stream指定的文件中
参数:
参1:需要写入文件的字符
参2:文件指针
返回值:
成功:成功写入文件的字符
失败:返回-1
在C语言中,EOF表示文件结束符(end of file)。这种以EOF作为文件结束标志的文件,必须是文本文件。
feof()函数既可用以判断二进制文件又可用以判断文本文件
int feof(FILE * stream);
功能:检测是否读取到了文件结尾。判断的是最后一次“读操作的内容”,不是当前位置内容(上一个内容)。
参数:文件指针
返回值:
非0值:已经到文件结尾
0:没有到文件结尾
fgetc()函数
int fgetc(FILE * stream);
功能:从stream指定的文件中读取一个字符
参数:文件指针
返回值:
成功:返回读取到的字符
失败:-1
#include <stdio.h>
int main()
{
//打开文件
FILE *fp = fopen("./test","w+");
if(fp == NULL)
{
perror("open err");
return -1;
}
//写文件
char buf[] = "this is a test for fputc";
int i = 0;
int n = strlen(buf);
for (i = 0; i < n; i++)
{
//往文件fp写入字符buf[i]
int ch = fputc(buf[i], fp);
printf("ch = %c\n", ch);
}
//读文件
char ch;
while(!feof(fp))
{
ch = fgetc(fp);
printf("%c",ch);
}
//关闭文件
fclose(fp);
return 0;
}
按照行读写文件fgets、fputs
fputs()函数
int fputs(const char * str, FILE * stream);
功能:将str所指定的字符串写入到stream指定的文件中,字符串结束符 '\0' 不写入文件。
参数:
参1:字符串
参2:文件指针
返回值:
成功:0
失败:-1
fgets()函数
char * fgets(char * str, int size, FILE * stream);
功能:从stream指定的文件内读入字符,保存到str所指定的内存空间,直到出现换行字符、读到文件结尾或是已读了size - 1个字符为止,最后会自动加上字符 '\0' 作为字符串结束。
参数:
参1:字符串
参2:指定最大读取字符串的长度(size - 1)
参3:文件指针
返回值:
成功:成功读取的字符串
读到文件尾或出错: NULL
#include <stdio.h>
int main()
{
FILE *fp = fopen("./test","w+");
if(fp == NULL)
{
perror("fopen err");
return -1;
}
//写文件
char *buf[] = { "123456\n", "bbbbbbbbbb\n", "ccccccccccc\n" };
int i = 0;
int n = 3;
for (i = 0; i < n; i++)
{
int len = fputs(buf[i], fp);
printf("len = %d\n", len);
}
//读文件
char buf[100] = 0;
while (!feof(fp)) //文件没有结束
{
memset(buf, 0, sizeof(buf));
char *p = fgets(buf, sizeof(buf), fp);
if (p != NULL)
{
printf("buf = %s", buf);
}
}
fclose(fp);
return 0;
}
按照格式化文件fprintf、fscanf
fprintf()函数
int fprintf(FILE * stream, const char * format, ...);
功能:根据参数format字符串来转换并格式化数据,然后将结果输出到stream指定的文件中,指定出现字符串结束符 '\0' 为止。
参数:
参1:文件指针
参2:字符串格式,用法和printf()一样
返回值:
成功:实际写入文件的字符个数
失败:-1
fscanf()函数
#include <stdio.h>
int fscanf(FILE * stream, const char * format, ...);
功能:从stream指定的文件读取字符串,并根据参数format字符串来转换并格式化数据。
参数:
参1:文件指针
参2:字符串格式,用法和scanf()一样
返回值:
成功:参数数目,成功转换的值的个数
失败: - 1
#include <stdio.h>
int main()
{
FILE *fp = fopen("./test","w+");
if(fp == NULL)
{
perror("fopen err");
return -1;
}
//写文件
fprintf(fp, "%d %d %d\n", 1, 2, 3);
//读文件
int a = 0;
int b = 0;
int c = 0;
fscanf(fp, "%d %d %d\n", &a, &b, &c);
printf("a = %d, b = %d, c = %d\n", a, b, c);
fclose(fp);
return 0;
}
按照块读写文件fread、fwrite
fwrite()函数
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:以数据块的方式给文件写入内容
参数:
参1:准备写入文件数据的地址
参2: size_t 为 unsigned int类型,此参数指定写入文件内容的块数据大小
参3:写入文件的块数,写入文件数据总大小为:size * nmemb
参4:已经打开的文件指针
返回值:
成功:实际成功写入文件数据的块数目,此值和nmemb相等
失败:0
fread()函数
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:以数据块的方式从文件中读取内容
参数:
参1:存放读取出来数据的内存空间
参2: size_t 为 unsigned int类型,此参数指定读取文件内容的块数据大小
参3:读取文件的块数,读取文件数据总大小为:size * nmemb
参4:已经打开的文件指针
返回值:
成功:实际成功读取到内容的块数,如果此值比nmemb小,但大于0,说明读到文件的结尾。
失败:0
//写文件
typedef struct Stu
{
char name[50];
int id;
}Stu;
Stu s[3];
int i = 0;
for (i = 0; i < 3; i++)
{
sprintf(s[i].name, "stu%d%d%d", i, i, i);
s[i].id = i + 1;
}
int ret = fwrite(s, sizeof(Stu), 3, fp);
printf("ret = %d\n", ret);
//读文件
typedef struct Stu
{
char name[50];
int id;
}Stu;
Stu s[3];
int ret = fread(s, sizeof(Stu), 3, fp);
printf("ret = %d\n", ret);
int i = 0;
for (i = 0; i < 3; i++)
{
printf("s = %s, %d\n", s[i].name, s[i].id);
}
03. 随机位置读文件
文件读写指针,在一个文件内只有一个
fseek()函数
int fseek(FILE *stream, long offset, int whence);
作用:移动光标的读写位置
参数:
参1:文件指针
参2:偏移量(矢量 +向后 -向前)
参3:
SEEK_SET:从文件开头位置移动
SEEK_CUR:从文件当前位置移动
SEEK_END:从文件末尾位置移动
返回值:
成功,0
失败,-1
ftell()函数
long ftell(FILE* stream);
作用:获取光标的位置
参数:文件指针
返回值:
成功,当前文件光标的读写位置
失败,-1
作用:ftell() + fseek(SEEK_END),来获取文件大小。
rewind()函数
void rewind(FILE *stream);
功能:把文件光标的读写位置移动到文件开头
参数:文件指针
返回值:无返回值
测试fseek()、ftell()、rewind()
#include <stdio.h>
int main()
{
//打开文件
FILE *fp = fopen("test.txt","r");
if(!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
//移动文件光标
fseek(fp,-1,SEEK_END); //从文件末尾开始,向前移动1个距离
int a = ftell(fp); //返回光标所在的位置
rewind(fp); //将光标移到到文件开头
//关闭文件
fclose(fp);
return 0;
}
04. Windows和Linux文本文件的区别
-
对于二进制文件操作,Windows使用"b"。 Linux下二进制和文本没区别
-
Windows下,回车\r、换行\n,\r\n 。Linux下回车换行都是\n
-
对文件指针,先写后读,Windows和Linux效果一致。
先读后写,Windows下需要使用fseek(fp,0,SEEK_CUR)来获取文件光标,才生效。Linux下无需修改
05. 获取文件大小stat()
虽然可以通过fseek(fp,0,SEEK_END) + ftell(fp)获取文件大小,但是打开文件对于系统而言,系统的资源消耗较大。所以可以用stat()函数来获取文件大小
int stat(const char* path,struct stat *buf);
功能:获取文件状态信息
参数:
参1:访问文件的路径或文件名
参2:保存文件信息的结构体
返回值:
成功,0
失败,-1
stat结构体原型(Linux系统下)
struct stat {
dev_t st_dev; //文件的设备编号
ino_t st_ino; //节点
mode_t st_mode; //文件的类型和存取的权限
nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
dev_t st_rdev; //(设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; //文件字节数(文件大小)
unsigned long st_blksize; //块大小(文件系统的I/O 缓冲区大小)
unsigned long st_blocks; //块数
time_t st_atime; //最后一次访问时间
time_t st_mtime; //最后一次修改时间
time_t st_ctime; //最后一次改变时间(指属性)
};
stat()测试
#include <sys/types.h> //stat()函数用到的头文件
#include <sys/stat.h> //stat()函数用到的头文件
#include <stdio.h>
int main()
{
struct stat st = { 0 };
int ret = stat("test.txt",&st); //传出参数:在函数调用结束时,充当函数的返回值
int fp_size = st.st_size; //不打开文件获取文件大小
printf("文件大小为:%d",fp_size);
return 0;
}
06. 删除文件remove()、重命名文件rename()
remove()函数
int remove(const char *pathname);
功能:删除文件
参数:文件名
返回值:
成功,0
失败,-1
rename()函数
int rename(const char *oldpath, const char *newpath);
功能:把oldpath的文件名改为newpath
参数:
参1:旧文件名
参2:新文件名
返回值:
成功,0
失败,-1
07. 文件缓冲区fflush()
标准输出 —— stdout —— 标准输出缓冲区。写给屏幕的数据,都是先存缓冲区,有缓冲区一次性刷新到物理设备(屏幕)
标准输入 —— stdin —— 标准输入缓冲区。从键盘读取的数据,直接读到缓冲区中,由缓冲区给程序提供数据。
简称:预读入、缓输出。
行缓冲:如printf(),遇到\n就会将缓冲区中的数据刷新到物理设备
全缓冲:如文件操作,缓冲区存满,数据刷新到物理设备上
无缓冲:如perror(),缓冲区中只要有错误(数据),就立即刷新到屋里设备
fflush()函数:手动刷新缓冲区
int fflush(FILE *stream);
功能:更新缓冲区,让缓冲区的数据立马写到文件中。
参数:文件指针
返回值:
成功,0
失败,-1
ffulsh()函数的使用
#include <stdio.h>
int main()
{
FILE *fp = fopen("test.txt","w+");
if(!fp)
{
perror("fopen error");
return -1;
}
char c = 0;
while(1)
{
scanf("%c",&c);
if(m == ':') //用户如果输入":" 则退出
{
break;
}
fputc(c,fp); //不是":",输入文件中去
fflush(fp); //手动刷新文件缓冲区到物理磁盘中,如果没有此函数,则当文件关闭时,才会自动刷新缓冲区。
}
//当文件关闭时,才会自动刷新缓冲区
fclose(fp);
return 0;
}