目录
1. 为什么使⽤⽂件?
如果没有⽂件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运⾏程序,是看不到上次程序的数据的,如果要将数据进⾏持久化的保存,我们可以使⽤⽂件。
2. 什么是⽂件?
磁盘(硬盘)上的⽂件是⽂件。
但是在程序设计中,我们⼀般的⽂件有两种:程序⽂件、数据⽂件(从⽂件功能的⻆度来分类
的)。
2.1 程序⽂件
程序⽂件包括源程序⽂件(后缀为.c),
⽬标⽂件(windows环境后缀为.obj),
可执⾏程序(windows 环境后缀为.exe)。
2.2 数据⽂件
⽂件的内容不⼀定是程序,⽽是程序运⾏时读写的数据,⽐如程序运⾏需要从中读取数据的⽂件,或者输出内容的⽂件。
2.3 ⽂件名
⼀个⽂件要有⼀个唯⼀的⽂件标识,以便⽤⼾识别和引⽤。
⽂件名包含3部分:⽂件路径+⽂件名主⼲+⽂件后缀
例如: c:\code\test.txt
为了⽅便起⻅,⽂件标识常被称为⽂件名。
3. ⼆进制⽂件和⽂本⽂件?
根据数据的组织形式,数据⽂件被称为 ⽂本⽂件 或者 ⼆进制⽂件 。
数据在内存中以⼆进制的形式存储,如果 不加转换的输出 到外存的⽂件中,就是 ⼆进制⽂件 。
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以 ASCII字符 的形式存储的⽂件就是⽂本⽂件。
⼀个数据在⽂件中是怎么存储的呢?
字符⼀律以ASCII形式存储,数值型数据既可以⽤ASCII形式存储,也可以使⽤⼆进制形式存储。
4. ⽂件的打开和关闭
4.1 流和标准流
4.1.1 流
我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输⼊输出 操作各不相同,为了 ⽅便 程序员对各种设备进⾏⽅便的操作,可以把 流 想象成 流淌着字符的河 。
C程序针对⽂件、画⾯、键盘等的数据输⼊输出操作 都是通过流操作 的。
⼀般情况下,我们要想向流⾥写数据,或者从流中读取数据,都是要打开流,然后操作。
4.1.2 标准流
那为什么我们从键盘输⼊数据,向屏幕上输出数据,并没有打开流呢?
那是因为C语⾔程序在启动的时候,默认打开了3个流:
- stdin - 标准输⼊流,在⼤多数的环境中从键盘输⼊,scanf函数就是从标准输⼊流中读取数据。
- stdout - 标准输出流,⼤多数的环境中输出⾄显⽰器界⾯,printf函数就是将信息输出到标准输出流中。
- stderr - 标准错误流,⼤多数环境中输出到显⽰器界⾯。
这是默认打开了这三个流,我们使⽤scanf、printf等函数就可以 直接 进⾏输⼊输出操作的。
stdin、stdout、stderr 三个流的类型是: FILE * ,通常称为⽂件指针。
C语⾔ 中,就是通过 FILE* 的⽂件指针来维护流的各种操作的。
4.2 ⽂件指针
缓冲⽂件系统中,关键的概念是“⽂件类型指针”,简称“ ⽂件指针 ”。
每个被使⽤的⽂件都在内存中开辟了⼀个相应的⽂件信息区,⽤来存放⽂件的相关信息(如⽂件的名字,⽂件状态及⽂件当前的位置等)。这些信息是保存在⼀个 结构体变量 中的。该结构体类型是由系统声明的,取名 FILE .
创建⼀个FILE*的指针变量:
FILE* pf;//⽂件指针变量
定义pf是⼀个 指向FILE类型数据的指针变量 。可以使pf指向某个⽂件的⽂件信息区(是⼀个结构体变量)。通过该⽂件信息区中的信息就能够访问该⽂件。也就是说,通过⽂件指针变量能够 间接找到 与它关联的⽂件。
比如:

4.3 ⽂件的打开和关闭
⽂件在读写之前应该先打开⽂件,在使⽤结束之后应该关闭⽂件。
在编写程序的时候,在打开⽂件的同时,都会返回⼀个 FILE*的指针变量 指向该⽂件,也相当于建⽴了 指针和⽂件的关系 。
ANSI C 规定使⽤ fopen 函数 来打开⽂件, fclose函数 来关闭⽂件。
//打开⽂件
FILE * fopen ( const char * filename, const char * mode );
//关闭⽂件
int fclose ( FILE * stream );
mode表⽰⽂件的打开模式,下⾯都是⽂件的打开模式:
文件使用方式 | 含义 | 如果文件不存在 |
“r”(只读)
|
为了输⼊数据,打开⼀个已经存在的⽂本⽂件
|
出错
|
“w”(只写)
|
为了输出数据,打开⼀个⽂本⽂件
|
建⽴⼀个新的⽂件
|
“a”(追加)
|
向⽂本⽂件尾添加数据
|
建⽴⼀个新的⽂件
|
“rb”(只读)
|
为了输⼊数据,打开⼀个⼆进制⽂件
|
出错 |
“wb”(只写)
|
为了输出数据,打开⼀个⼆进制⽂件
|
建⽴⼀个新的⽂件 |
“ab”(追加)
|
向⼀个⼆进制⽂件尾添加数据
|
建⽴⼀个新的⽂件 |
“r+”(读写)
|
为了读和写,打开⼀个⽂本⽂件
|
出错 |
“w+”(读写)
|
为了读和写,建议⼀个新的⽂件
|
建⽴⼀个新的⽂件 |
“a+”(读写)
|
打开⼀个⽂件,在⽂件尾进⾏读写
|
建⽴⼀个新的⽂件
|
“rb+”(读写)
|
为了读和写打开⼀个⼆进制⽂件
|
出错 |
“wb+”(读
写)
|
为了读和写,新建⼀个新的⼆进制⽂件
|
建⽴⼀个新的⽂件
|
“ab+”(读
写)
|
打开⼀个⼆进制⽂件,在⽂件尾进⾏读和写
|
建⽴⼀个新的⽂件
|
如:
#include <stdio.h>
int main ()
{
FILE * pFile;
//打开⽂件
pFile = fopen ("myfile.txt","w");
//⽂件操作
if (pFile!=NULL)
{
fputs ("fopen example",pFile);
//关闭⽂件
fclose (pFile);
}
return 0;
}
5. ⽂件的顺序读写
5.1 顺序读写函数
函数名 | 功能 | 适用于 |
fgetc | 字符输入函数 | 所有的输入流 |
fputc | 字符输出函数 | 所有输出流 |
fgets | 文本行输入函数 | 所有输入流 |
fputs | 文本行输出函数 | 所有输出流 |
fscanf | 格式化输入函数 | 所有输入流 |
sprintf |
格式化输出函数 | 所有输出流 |
fread | 二进制输入 | 文件输入流 |
fwrite | 二进制输出 | 文件输出流 |
fgetc函数
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
//打开文件
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
int ch = 0;
while ( (ch = fgetc(pf) )!= EOF )
{
printf("%c", ch);
}
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fputc函数
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
//打开文件
FILE* pf = fopen("text.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
//fputc('a',pf);
//fputc('b',pf);
//fputc('c',pf);
char ch = 0;
for (ch = 'a'; ch <= 'z'; ch++)
{
fputc(ch, pf);
}
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fgets函数
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//⽂本⾏输⼊函数
int main()
{
//打开文件
FILE* pf = fopen("text.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
char arr[20] = { 0 };
while (fgets(arr, 20, pf) != NULL)
{
printf("%s", arr);
}
//关闭文件
fclose(pf);
pf == NULL;
return 0;
}
fputs函数
//⽂本⾏输出函数
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
//1.打开文件
FILE* pf = fopen("text.txt", "w");
if (pf==NULL)
{
perror("fopen");
return 1;
}
//写文件
fputs("hello world\n",pf);
fputs("hello bits",pf);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
6. ⽂件的随机读写
6.1 fseek
根据⽂件指针的位置和偏移量来定位⽂件指针(⽂件内容的光标)。
int fseek ( FILE * stream, long int offset, int origin );
例:
#include<stdio.h>
int main ()
{
FILE * pFile;
pFile = fopen ( "example.txt" , "wb" );
fputs ( "This is an apple." , pFile );
fseek ( pFile , 9 , SEEK_SET );
fputs ( " sam" , pFile );
fclose ( pFile );
return 0;
}
6.2 ftell
返回⽂件指针相对于起始位置的偏移量
long int ftell ( FILE * stream );
例:
#include <stdio.h>
int main ()
{
FILE * pFile;
long size;
pFile = fopen ("myfile.txt","rb");
if (pFile==NULL)
perror ("Error opening file");
else
{
fseek (pFile, 0, SEEK_END); // non-portable
size=ftell (pFile);
fclose (pFile);
printf ("Size of myfile.txt: %ld bytes.\n",size);
}
return 0;
}
6.3 rewind
让⽂件指针的位置回到⽂件的起始位置
void rewind ( FILE * stream );
例:
#include <stdio.h>
int main ()
{
int n;
FILE * pFile;
char buffer [27];
pFile = fopen ("myfile.txt","w+");
for ( n='A' ; n<='Z' ; n++)
fputc ( n, pFile);
rewind (pFile);
fread (buffer,1,26,pFile);
fclose (pFile);
buffer[26]='\0';
printf(buffer);
return 0;
}