概述
保存于外存储器上(磁盘、U盘、移动硬盘)的数据集合。
文件内容的读取、写入(视为对文件输入输出操作,像流一样,称为文件流);
c语言采用“文件缓冲机制”,系统为文件创建“文件缓冲区”;
按存储方式划分:文本文件(ASCII文件)和 二进制文件
文件系统中:路径+文件名,举例:d:/aaa/bbb/ccc
c语言程序中:文件指针,语法:FILE *指针变量名
打开文件
文件处理(读写)
关闭文件
文件的操作
让系统为文件创建文件缓冲区
函数名:fopen
头文件:#include
函数原型:FILE* fopen(const char *path,const char *mode);
返回值类型 函数名 参数
函数功能:打开文件,为文件创建缓冲区
函数参数:
path
:目标文件路径
mode
:文件打开方式(读、写、读写)
返回值:
成功:返回文件指针File*
(缓冲区首地址)
失败:返回NULL
文件使用完毕,一定要释放
函数名:fclose
头文件:#include
函数原型:int fclose(FILE* fp)
函数功能:关闭文件,释放缓冲区
函数参数:
fp
:已经打开的文件指针
返回值:
成功:返回0
失败:返回EOF(-1)
文件打开关闭案例:
#include
int main(int argc, char** argv)
{
//在命令行执行可执行文件时,传递一个需要打开的目标文件地址,进行参数判断
if(argc < 2)
{
printf("输入有误,请按照 <%s 文件路径> 格式输入\n", argv[0]);
return -1;
}
//根据文件路径,打开文件,mode(r,w,rw)
FILE* fp = fopen(argv[1],"r");
//检验文件是否打开成功
if(!fp)
{
perror("文件打开失败!");
return -1;
}
puts("文件打开成功!\n");
// 关闭打开的文件
int ret = fclose(fp);
// 校验文件是否关闭成功(很多时候这一步会省略掉)
/*
if(ret == -1)
{
perror("文件关闭失败!");
return -1;
}
puts("文件关闭成功!");
*/
return 0;
}
单字符读取
函数名:fgetc
头文件:#include
函数原型:int fgetc(File* fp);
函数功能:从fp
代表文件中获取一个字符
函数参数:
fp
:我们需要操作的文件
返回值:
成功:返回读取到的字符
失败:或文件末尾,返回EOF
(-1)
单字符读取案例:
#include
int main(int argc, char ** argv)
{
if(argc < 2)
{
printf("输入有误,请按照 <%s 文件路径> 格式输入\n", argv[0]);
return -1;
}
FILE* fp = fopen(argv[1],"r");
if(!fp)
{
perror("文件打开失败!");
return -1;
}
int re = 0;
while(re != -1 && re != '\n')
{
re = fgetc(fp);
printf("%c", re);
}
//方式二
/*
char ch;
while( (ch = fgetc(fp)) != EOF)
{
printf("%c", ch);
}
*/
printf("\n");
fclose(fp);
return 0;
}
多字符读取
函数名:fgets
头文件:#include
函数原型:char *fgets(char *buf, int size, FILE *fp);
函数功能:从fp
代表文件获取size
个字符,放置到buf
代表内存中
函数参数:
buf
:内存空间首地址用于存放读取的字节
size
:待读取的字符,实际读取size-1
fp
:已经打开的文件指针
返回值:
成功:返回buf
失败:文件末尾,返回NULL
多字符读取案例:
#include
#include
int main(int argc, char** argv)
{
if(argc < 2)
{
printf("输入有误,请按 <%s 文件路径> 格式输入\n", argv[0]);
return -1;
}
FILE* fp = fopen(argv[1], "rw");
if(!fp)
{
perror("文件打开失败!");
return -1;
}
//创建缓冲区
char buf[64] = {0};
while(fgets(buf,64,fp) != NULL)
{
printf("%s",buf);
//给缓冲区清空
memset(buf,0,sizeof(buf));
}
printf("\n");
fclose(fp);
return 0;
}
单字符写入
函数名:fputc
头文件:#include
函数原型:int fputc(int c,File* fp);
函数功能:向fp
代表文件中写入一个字符c
函数参数:
c
:待写入字符
fp
:已经打开的文件
返回值:
成功:返回读取到的字符
失败:或文件末尾,返回EOF
(-1)
单字符写入案例:
#include
int main(int argc, char** argv)
{
if(argc < 3)
{
printf("输入有误,请按 <%s 文件路径> 格式输入\n", argv[0]);
return -1;
}
FILE* fp = fopen(argv[1], "w");
if(!fp)
{
perror("文件打开失败!");
return -1;
}
//单个字符循环写入
while(*argv[2] != '\0')
{
// ./a.out file1.txt I_LOVE_YOU
fputc(*argv[2],fp);
argv[2]++;
}
fclose(fp);
return 0;
}
多字符写入
函数名:fputs
头文件:#include
函数原型:int fputs(const char *buf, FILE *fp);
函数功能:向fp
代表的文件中写入一个字符数组s
函数参数:
s
:待写入的字符数组(写入缓冲区)
fp
:已打开的文件指针
返回值:
成功:返回非负整数 (> 0)
失败:返回EOF(-1)
多字符写入案例:
#include
int main(int argc,char **argv)
{
if(argc < 3)
{
printf("输入有误,请按照<%s 文件路径 文本数据>格式输入\n",argv[0]);
return -1;
}
FILE* fp = fopen(argv[1],"w");
if(!fp)
{
perror("文件打开失败!");
return -1;
}
// ./a.out file1.txt I_Love_Your
fputs(argv[2],fp);
fclose(fp);
return 0;
}
函数名: feof(fp)
头文件:#include
函数原型:int feof(fp)
函数功能:在读fp
指向的文件时判断是否遇到文件结束。
函数参数:
fp
:已打开的文件指针
返回值:
文件未读取完毕:返回0
失败或文件读取完毕:返回非0
案例:
#include
#include
int main(int argc,char** argv)
{
if(argc < 3)
{
printf("输入有误,请按照<%s 源文件路径 目标文件路径>格式输入\n",argv[0]);
return -1;
}
FILE* in = fopen(argv[1],"r");
FILE* out = fopen(argv[2],"w");
if(!in || !out)
{
perror("文件打开失败!");
return -1;
}
// 单字符读写
// while(!feof(in))
// {
// 读写操作
// fputc(fgetc(in),out);
//}
char buf[64] = {0};
// 使用循环读写文件
while(fgets(buf,64,in)!=NULL)
{
// 写入数据
fputs(buf,out);
// 重置缓冲区
memset(buf,0,sizeof(buf));
}
printf("\n");
// 关闭文件
fclose(in);
fclose(out);
}
fread
头文件:#include
函数原型:size_t fread(void *ptr,size_t size,size_t count,FILE* fp)
函数功能:从fp
代表的文件中以size为单位(一个数据块)读取count
个数据块存放在ptr
内存 中。
函数参数:
ptr
:内存空间首地址,用于存放读取到数据(缓冲区)
size
:数据块大小,以byte为单位
count
:待读取的数据块的个数
fp
:已打开的文件指针
返回值:
成功:返回实际写入的字节数
失败:返回 < 0
案例:
#include
#define SIZE 4
// 创建学生结构体
struct Student
{
char name[20];
int num;
int age;
char addr[50];
} stud[SIZE];
void main()
{
int i;
FILE* fp;
if((fp = fopen("stu-list","rb")) == NULL)
{
perror("文件打开失败!");
return;
}
// 循环读取二进制文件
for(i = 0; i < SIZE; i++)
{
fread(&stud[i],sizeof(struct Student),1,fp);
// 将读到的内容输出到控制台
printf("%-10s%4d%4d%-20s\n",stud[i].name,stud[i].num,stud[i].age,stud[i].addr);
}
fclose(fp);
}
fwrite
头文件:#include
函数原型:size_t fwrite(const void* ptr,size_t size,size_t count,FILE* fp)
函数功能:向fp
代表的文件中以size
为一个数据块,写入count
个数据块到fp
函数参数:
ptr
:内存空间首地址,用于存放待写入的数据,(写入缓冲区)
size
:数据块大小,以byte为单位
count
:待写入的数据块个数
fp
:已打开的文件指针
返回值:
成功:返回实际写入字节数
失败:写入完毕,返回 < 0
案例:
从键盘输入4个学生的有关数据,然后把它们转存到磁盘文件上去
#include
#define SIZE 4 // 学生数量
// 创建学生结构体
struct Student
{
char name[20];
int num;
int age;
char addr[50];// 住址
} stud[SIZE];
// 保存学生信息到文件
void save()
{
FILE* fp;
int i;
if((fp = fopen("stu-list","wb")) == NULL)// stu-list对应的目录:./stu-list,wb-二进制写
入,默认是文本写入
{
perror("文件打开失败!");
return;
}
// 写入操作
for(i = 0; i < SIZE; i++)
{
fwrite(&stud[i],sizeof(struct Student),1,fp);
}
// 关闭文件
fclose(fp);
}
void main()
{
int i;
printf("请输入学生的信息:姓名,学号,年龄,住址\n");
for(i = 0; i < SIZE;i++)
{
scanf("%s%d%d%s",stud[i].name,&stud[i].num,&stud[i].age,stud[i].addr);
// 录入一个学生,就保存一个学生到文件中
save();
}
}
说明:读写文件内容时,可在指定的位置上读写数据
文件随机读写的核心操作: 文件位置指针的定位
文件位置指针的移动方法:
rewind
头文件:#include
函数原型: void rewind(FILE* fp);
函数功能: 将文件位置指针定位到文件开头
函数参数:
fp
: 已经打开的文件指针
返回值: 无
fseek
头文件: #include
函数原型: int fseek(FILE *fp, long offset, int whence);
函数功能: 将文件位置指针定位到指定位置
函数参数:
fp
: 已经打开的文件指针
offset
: 相对于参考位置的偏移位置
whence
: 参考位置
SEEK_SET 或 0 表示文件头
SEEK_CUR 或 1 表示当前读写的位置
SEEK_END 或 2 表示文件尾
返回值:
成功 :0
失败 : -1
ftell
头文件: #include
函数原型: long ftell(FILE *fp);
函数功能: 获取文件位置指针当前位置
函数参数:
fp
: 已经打开的文件指针
返回值:
成功 :文件位置指针当前位置
失败 : -1
案例一:
有一个磁盘文件,第一次将它的内容显示在屏幕上,第二次把它复制到另一文件上
#include
void main()
{
FILE *fp1, *fp2;
fp1 = fopen("file1.c", "r");
fp2 = fopen("file2.c", "w");
while (!feof(fp1))
putchar(getc(fp1)); /*输出到屏幕*/
rewind(fp1); /*位置指针返回到文件头*/
while (!feof(fp1))
putc(getc(fp1), fp2); /*从文件file1的头读起,输出到文件file2中*/
fclose(fp1);
fclose(fp2); /*关闭文件*/
案例二:
存有10个学生的数据。要求将第1、3、5、7、9个学生数据输入计算机,并在屏幕上显示出来
#include
#include
struct student_type
{
char name[10];
int num;
int age;
char sex;
} stud[10];
void main()
{
int i;
FILE *fp;
if ((fp = fopen("stud-dat", "rb")) == NULL)
{
printf("can not open file\n");
return;
}
for (i = 0; i < 10; i += 2)
{
fseek(fp, i * sizeof(struct student_type), 0);
fread(&stud[i], sizeof(struct student_type), 1, fp);
printf("%s %d %d %c\n", stud[i].name, stud[i].num, stud[i].age, stud[i].sex);
}
fclose(fp);
}
案例三:
用“追加”的形式打开文件gg.txt,查看文件读写指针的位置,然后向文件写入“data”,再查看文件读写指针的位置。
#include "stdio.h"
main()
{
long p;
FILE *fp;
if ((fp = fopen("gg.txt","a")) == NULL)
{
printf("cannot open this file!\n");
return;
}
p = ftell(fp);
printf("p=%ld\n",p);
fputs("data", fp);
p = ftell(fp);
printf("p=%ld\n",p);
fclose(fp);
}