FILE指针
C语言,每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及 文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE. 例如,VS2008编译环境提供的stdio.h 头文件中有以下的文件类型申明:
struct _iobuf{
char*_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char*_tmpfname;
};
typedef struct _iobuf FILE;
不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。 每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关 心细节。 一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。
打开关闭文件
打开文件
fopen函数原型:
FILE *fopen(const char *path, const char *mode);
参数:第一个参数是文件路径,第二个参数是打开文件的方式,类型均为字符串
使用示例
pFile = fopen("myfile.txt", "w");
#include <stdio.h>
int main(){
FILE* pFile;
pFile = fopen("myfile.txt", "w");
if (pFile != NULL) {
fputs("fopen example", pFile);
fclose(pFile);
}
return 0;
}
若是没有这个文件,便会创建一个文件
第二个参数选择
文件使用方式 | 含义 | 如果指定文件不存在 |
---|---|---|
“r”(读) | 打开文件用于读 | 出错 |
“w”(写) | 将文件截断为零长度或创建文本文件以进行写入 | 建立一个新的文件 |
“rt”(只读) 1 | 打开一个文本文件,只允许读数据 | 出错 |
“wt”(只写) | 只写打开或建立一个文本文件,只允许写数据 | 建立一个新文件 |
“a”(追加) | 向文本文件尾追加数据 | 出错 |
“rb”(追加) | 打开一个二进制文件读 | 出错 |
“wb”(只写) | 打开一个二进制文件写 | 建立一个新的文件 |
“ab”(追加) | 向一个二进制文件尾添加数据 | 出错 |
“r+”(读写) | 为了读和写,打开一个文本文件 | 出错 |
“w+”(读写) | 为了读和写,建立一个新的文件 | 建立一个新文件 |
“a+”(读写) | 打开一个文件,在文件尾进行读写 | 建立一个新的文件 |
“rb+”(读写) 2 | 为了读和写打开一个二进制文件 | 出错 |
“wb+”(读写) | 为了读和写,新建一个新的二进制文件 | 建立一个新的文件 |
“ab+”(读写) | 打开一个二进制文件,在文件尾进行读和写 | 建立一个新的文件 |
关闭文件
fclose函数原型:
int fclose(FILE *stream);
参数:唯一的一个参数是需要关闭的文件指针
文件读写
顺序读写
功能 | 函数名 | 适用于 |
---|---|---|
字符输出函数 | fputc | 所有输出流 |
字符输入函数 | fgetc | 所有输入流 |
文本行输出函数 | fputs | 所有输出流 |
文本行输入函数 | fgets | 所有输入流 |
格式化输出函数 | fprintf | 所有输出流 |
格式化输入函数 | fscanf | 所有输入流 |
二进制输出 | fwrite | 文件 |
二进制输入 | fread | 文件 |
fputc函数原型:
int fputc( int c, FILE *stream );
参数:第一个参数是要写入的字符,第二个参数是要写入的文件流
使用示例
FILE* pFile = fopen("fputc.txt", "w");
char* str = "This is a test of fputc!!\n";
char* p_str = str;
while ((*p_str != '\0') && fputc(*(p_str++), stdout) != EOF);
p_str = str;
while ((*p_str != '\0') && fputc(*(p_str++), pFile) != EOF);
FILE指针其实就是文件流,也是流的一种,与标准输入输出流使用起来差不多
fgetc函数原型:
int fgetc( FILE *stream );
参数:stream是要读取的目的流
使用示例
//先使用fputs写一个文本文件
FILE* pFile = fopen("fgetc.txt", "w");
char* str = "This is a test of fgetc!!\n";
fputs("Hello world from fgetc.\n", pFile);
fclose(pFile);
//使用fgetc读取这个文本文件的内容
pFile = fopen("fgetc.txt", "r");
while(feof(pFile) == 0){
char ch = fgetc(pFile);
fputc((char)ch, stdout);
}
fclose(pFile);
fputs函数原型:
int fputs( const char *string, FILE *stream );
参数:第一个是要写入文件的字符串,第二个参数是输出流
使用示例
FILE* pFile = fopen("fputs.txt", "w");
char* str = "This is a test of fputs!!\n";
fputs(str, pFile);
fgets函数原型:
char *fgets(char *restrict s, int n, FILE *restrict stream);
参数:从stream流中读取最大n个字符量的字符串保存到s字符中
使用示例
//先使用fputs写入一个文本文件
FILE* pFile = fopen("fgets.txt", "w");
char* str = "This is a test of fgets!!\n";
fputs(str, pFile);
fclose(pFile);
//再使用fgets读
char line[1000];
if ((pFile = fopen("fgets.txt", "r")) != NULL)
{
if (fgets(line, 1000, pFile) == NULL)
printf("fgets error\n");
else
printf("%s", line);
fclose(pFile);
}
fprintf函数原型:
int fprintf( FILE *stream, const char *format [, argument ]...);
参数:stream要输出的流,format是格式控制字符串,argument是多个变量
使用示例
int i = 10;
double fp = 1.5;
char s[] = "this is a string";
char c = '\n';
FILE* stream = fopen("fprintf.out", "w");
fprintf(stream, "%s%c", s, c);
fprintf(stream, "%d\n", i);
fprintf(stream, "%f\n", fp);
fclose(stream);
system("type fprintf.out");
与标准输出的printf区别在于多了第一个指定输出的流参数,out后缀文件内容直接可以使用system打印到标准输出流
fscanf函数原型:
int fscanf( FILE *stream, const char *format [, argument ]... );
参数:从stream流按format格式解析数据依次存储到arguments中
使用示例
//先使用fprintf向文件输入
int i = 10;
double fp = 1.5;
char s[] = "string";
char c = 'U';
FILE* stream = fopen("fscanf.out", "w");
fprintf(stream, "%s %c", s, c);
//s字符串需要scanf读取的话,没有空格和换行的字符串请用空格与后面的变量隔开,如果字符串含空格,建议将字符串作为一整行用fgets读取
fprintf(stream, "%d\n", i);
fprintf(stream, "%f\n", fp);
fclose(stream);
//使用fscanf读取文件数据
stream = fopen("fscanf.out", "r");
fscanf(stream, "%s", &s);
fscanf(stream, "%c", &c); //捕捉空格
fscanf(stream, "%c", &c);
printf("%s %c\n", s, c);
fscanf(stream, "%d", &i);
fscanf(stream, "%f", &fp);
printf("%d\n%f\n", i, fp);
fclose(stream);
fwrite函数原型:
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
参数:buffer是将要被写的数据,size是元素字节大小,count是元素个数,stream是要写的目的流
使用示例
FILE* stream = fopen("fwrite.out", "w+t");
char list[] = "abcdefghijklmnopqrstuvwxyz";
if (stream != NULL) {
char numwritten = fwrite(list, sizeof(char), strlen(list), stream);
printf("Wrote %d items\n", numwritten);
fclose(stream);
}
system("type fread.out");
fwrite可以写入count个字符、整形或者size大小的字符串
fread函数原型:
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
参数:buffer是读取的数据存储区,size是单个元素大小,count是
使用示例
//读取上面fwrite保存的fwrite.out文件
if ((stream = fopen("fwrite.out", "r+t")) != NULL)
{
char numread = fread(list, sizeof(char), 26, stream);
printf("Number of items read = %d\n", numread);
printf("Contents of buffer = %.26s\n", list);
fclose(stream);
}
else
printf("File could not be opened\n");
随机读写
文件指针跳转任意位置
fseek函数原型
int fseek(FILE * stream, long int offset, int origin);
参数:stream是所操作的流,offset是偏移量,origin是基准偏移起始位置
基准 | 偏移基准位置 |
---|---|
SEEK_SET | 文件起始 |
SEEK_CUR | 文件指针所指向的当前位置 |
SEEK_END | 文件结尾 |
使用示例
FILE* pFile = fopen("example.txt", "wb");
fputs("This is an apple.", pFile);
fseek(pFile, 9, SEEK_SET);
fputs(" sam", pFile);
fclose(pFile);
system("type example.txt");
返回文件指针相对于起始位置的偏移量
ftell函数原型
long ftell( FILE *stream );
参数:stream是得到偏移量的目标流
使用示例
FILE* stream = fopen("ftell.c", "w+");
srand(time(NULL));
int charNumber = 150;
while (charNumber--)
fputc(rand() % 57 + 65, stream);
//得到当前的偏移量
long position;
position = ftell(stream);
printf("Position after trying to read 100 bytes: %ld\n",
position);
fclose(stream);
文件指针的位置回到文件的起始位置
rewind函数原型
void rewind ( FILE * stream );
参数:stream是将文件指针指向文件起始的目标流
使用示例
//写一个文件用于测试
char list[100];
FILE* stream = fopen("rewind.c", "w");
srand(time(NULL));
int charNumber = 150;
while (charNumber--)
fputc(rand() % 57 + 65, stream);
fclose(stream);
stream = fopen("rewind.c", "r");
//读
fread(list, sizeof(char), 100, stream);
char position = ftell(stream);
printf("Position after read: %ld\n",
position);
//文件指针回到文件首
rewind(stream);
position = ftell(stream);
printf("Position after back to start: %ld\n",
position);
fclose(stream);
刚写完不关闭文件流读取文件指纹偏移量是负数
FILE* stream = fopen("rewind.c", "w");
srand(time(NULL));
int charNumber = 150;
while (charNumber--)
fputc(rand() % 57 + 65, stream);
char position = ftell(stream);
printf("Position after write: %ld\n", position);
文件结束判定
feof函数原型
int feof( FILE *stream );
参数:判断文件指针是否到达文件结尾的目标流
fgetc、fgetc、fread、fprintf当读到文件结尾时就会返回EOF
使用示例
//创建feof.c
FILE* stream = fopen("feof.c", "w");
srand(time(NULL));
int charNumber = 80;
while (charNumber--)
fputc(rand() % 57 + 65, stream);
fclose(stream);
//读feof.c
int count, total = 0;
char buffer[100];
if ((stream = fopen("feof.c", "r")) == NULL)
exit(1);
//结合feof就可以循环读到文件结尾
/* Cycle until end of file reached: */
while (!feof(stream))
{
/* Attempt to read in 10 bytes: */
count = fread(buffer, sizeof(char), 100, stream);
if (ferror(stream)) {
perror("Read error");
break;
}
/* Total up actual bytes read */
total += count;
}
printf("Number of bytes read = %d\n", total);
fclose(stream);
读二进制文件示例
#include <stdio.h>
enum { SIZE = 5 };
int main(void)
{
double a[SIZE] = { 1.0,2.0,3.0,4.0,5.0 };
double b = 0.0;
size_t ret_code = 0;
FILE* fp = fopen("test.bin", "wb"); // 必须用二进制模式
fwrite(a, sizeof(*a), SIZE, fp); // 写 double 的数组
fclose(fp);
fp = fopen("test.bin", "rb");
// 读 double 的数组
while ((ret_code = fread(&b, sizeof(double), 1, fp)) >= 1)
{
printf("%lf\n", b);
}
if (feof(fp))
printf("Error reading test.bin: unexpected end of file\n");
else if (ferror(fp)) {
perror("Error reading test.bin");
}
fclose(fp);
fp = NULL;
}