文件指针
文件类型的指针 FILE*
当某个文件在程序中被调用时,编译器会为这个文件开辟一个空间,用以存储文件的信息,如文件的名字,文件状态及文件当前的位置等
这些信息是存在一个结构体中的,即开辟的空间就是为结构体准备的。而文件的信息就是结构体中的成员,文件本身则是一个结构体
例如,VS2013编译环境提供的 stdio.h 头文件中有如下的文件结构体类型申明:
struct _iobuf
{
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;
不同的编译器对FILE类型的定义不完全相同,但是大同小异
每当打开一个文件时,系统会根据文件的情况自动创建一个 FILE 结构的变量,并填充其中的信息
一般我们是通过 FILE 结构体类型的指针来使用这个 FILE 结构体类型的变量
FILE* pf; //文件指针变量
定义 pf 是一个用以存放 FILE 结构体类型地址的指针变量。
可以让 pf 指向文件对应的结构体,通过该结构体中的成员获取该文件的信息,就能访问该文件
文件的打开和关闭
fopen
//打开文件
FILE * fopen ( const char * filename, const char * mode );
功能:
file open 打开文件
参数:
filename 文件名,mode 打开方式,两者都以字符串的形式传入,即 char 类型指针
返回:
一个文件结构体类型指针,使我们可以通过这个指针对我们开启的文件进行一系列的操作
打开方式 mode:
mode | 功能 | 若我们要打开的文件不存在 |
' r ' (只读) | 为了输入数据,打开一个已经存在的文本文件 | 直接出错 |
' w ' (只写) | 为了输出数据,打开一个文本文件 | 建一个新的名字为 name 文件 |
' a ' (追加) | 向文本文件的尾部添加数据 | 建一个新的名字为 name 文件 |
' rb ' (只读) | 为了输入数据,打开一个已经存在的二进制文件 | 直接出错 |
' wb ' (只写) | 为了输出数据,打开一个二进制文件 | 建一个新的名字为 name 文件 |
' ab ' (追加) | 向二进制文件的尾部添加数据 | 直接出错 |
' r+ ' (读写) | 为了输入输出数据,打开一个已经存在的文本文件 | 直接出错 |
' w+ ' (读写) | 为了输入输出数据,新建一个文本文件 | 建一个新的名字为 name 文件 |
' a+ ' (读写) | 向文本文件的尾部进行读写操作 | 建一个新的名字为 name 文件 |
' rb+ ' (读写) | 为了输入输出数据,打开一个已经存在的二进制文件 | 直接出错 |
' wb+ ' (读写) | 为了输入输出数据,新建一个二进制文件 | 建一个新的名字为 name 文件 |
' ab+ ' (读写) | 打开一个二进制文件,在文件的尾部进行读写操作 | 建一个新的名字为 nameu |
注:’ ‘ 之中没有空格,笔者这里只是为了美观
fclose
//关闭文件
int fclose ( FILE * stream );
功能:
file close 关闭文件
参数:
stream 一个文件类型指针,其中存放着要关闭的文件结构体的地址
返回:
0 关闭失败,非 0 关闭成功
代码示例:
/* fopen fclose example */
#include <stdio.h>
int main ()
{
FILE * pFile;
//打开文件
pFile = fopen ("myfile.txt","w");
//文件操作
if (pFile!=NULL)
{
fputs ("fopen example",pFile);
//关闭文件
fclose (pFile);
}
return 0;
}
文件的顺序读写
不同输入输出函数的区别
scanf | fscanf | sscanf |
printf | fprintf | sprintf |
scanf | 从标准 输入流(stdin) 上进行格式化输入 | printf | 向标准 输出流(stdout) 上进行格式化输出 |
fscanf | 可以从 标准流/文件流 上读取格式化的数据 | fprintf | 把数据按照格式化的方式输出到 标准流/文件流 |
sscanf | 可以从 字符串 中提取格式化数据 | sprintf | 把一个格式化的数据转化成 字符串 |
文件的随机读写
fseek
int fseek ( FILE * stream, long int offset, int origin );
功能:
根据文件指针的位置和偏移量来定位文件指针
例子:
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;
}
ftell
long int ftell ( FILE * stream );
功能:
返回文件指针相对与起始位置的偏移量
例子:
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;
}
rewind
void rewind ( FILE * stream );
功能:
让文件指针的位置回到文件的起始位置
例子:
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';
puts (buffer);
return 0;
}
文件读取结束的判断
文本文件
文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
int main(void)
{
int c; // 注意:int,非char,要求处理EOF
FILE* fp = fopen("test.txt", "r");
if(!fp)
{
perror("File opening failed");
return EXIT_FAILURE;
}
//fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
{
putchar(c);
}
//判断是什么原因结束的
if (ferror(fp))
{
puts("I/O error when reading");
}
else if (feof(fp))
{
puts("End of file reached successfully");
}
fclose(fp);
}
二进制文件
enum { SIZE = 5 };
int main()
{
double a[SIZE] = {1.,2.,3.,4.,5.};
FILE *fp = fopen("test.bin", "wb"); // 必须用二进制模式
fwrite(a, sizeof *a, SIZE, fp); // 写 double 的数组
fclose(fp);
double b[SIZE];
fp = fopen("test.bin","rb");
size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 读 double 的数组
if(ret_code == SIZE)
{
puts("Array read successfully, contents: ");
for(int n = 0; n < SIZE; ++n)
{
printf("%f ", b[n]);
}
putchar('\n');
}
else
{ // error handling
if (feof(fp))
{
printf("Error reading test.bin: unexpected end of file\n");
}
else if (ferror(fp))
{
perror("Error reading test.bin");
}
}
fclose(fp);
return 0;
}