文件结构体和文件指针
// 在c语言中,对文件的操作一般是用库函数来实现的
// ANSI(美国国家标准学会)规定了标准的输入输出函数,用他们对文件进行读写以规范和提高编程效率
// 每个被使用的文件在内存中都会开辟一个区,用来存放文件的有关信息,而这些信息都保存在文件结构体FILE中
// FILE 用于访问一个流,若同时激活了几个流,那么每个流都有一个相应的FILE与之相关联
// 为了在流上执行一些操作,需要调用一些合适的库函数,并传递一个与流相关的FILE参数
// C语言定义了三个特别的文件指针常数,标准输入、标准输出、标准错误,流的名称分别为stdin、stdout、stderr,他们都是一个指向FILE的指针
typedef struct {
short level; //缓冲区,“满”或“空”的程度
unsigned flags; //文件状态的标志
char fd; //文件描述符
unsigned char hold; //如无缓冲区不读取字符
short basize; //缓冲区的大小
unsigned char *buffer; //数据缓冲区的位置
unsigned char *curp; //指针当前的指向
unsigned istemp; //临时文件,指示器
short token; //用于有效性的检验
} FILE;
// 有了结构体FILE,我们就可以用它来定义FILE类型的变量,用来存放待处理文件的信息
FILE arrayf[10];
// 我们还可以定义一个文件类型的指针,即指向文件的指针
FILE *fp;
标准流的I/O函数
数据类型 输入 输出 描述
----------------------------------------------------------
字符 getchar putchar 读取(写入)单个字符
文本行 fgets fputs 文本行未格式化的输入(输出)
scanf printf 文本行格式化的输入(输出)
----------------------------------------------------------
# include <stdio.h>
int main() {
char ch;
//char s[10];
//printf("请输入单个字符: ");
//ch = getchar();
//putchar(ch);
//printf("请输入单个字符串: ");
//fgets(s, sizeof(s)/sizeof(char), stdin);
//fputs(s, stdout);
printf("请输入一个字符: ");
scanf(" %c", &ch);
printf("%c\n", ch);
return 0;
}
常见文件操作函数
打开与关闭:fopen,fclose
读写字符:fgetc,fputc
读写字符串:fgets,fputs
按数据块读写:fread,fwrite
格式化读写:fscanf,fprintf
文件定位:fseek,rewind,ftell
判断文件是否结尾:feof
fopen
函数原型:FILE * fopen(char const *name, char *mode)
相关解释:用于打开一个特定的文件,并把一个流和这个文件相关联
fclose
函数原型:int fclose(FILE *fp)
相关解释:用于关闭一个特定的文件,所谓关闭就是使文件指针变量不再指向该文件,之后不能再通过该指针变量对文件进行读写操作。
对于输出流,fclose函数在文件关闭之前会刷新缓冲区,这里需要注意,在程序结束之前,我们一定要关闭所有已经打开
的文件,否则会产生数据的丢失。比如,在向文件写数据时,总是先将数据存到缓冲区,待缓冲区满后才将数据写入文件,
若缓冲区未满时程序结束,则缓冲区的数据将会丢失。使用fclose函数关闭文件,他会将缓冲区的数据写入文件,然后才
释放文件指针,从而可以避免文件的丢失。fclose有一个int类型的返回值,文件关闭成功时返回0,失败时返回EOF(-1)
fgetc
函数原型:int fgetc(FILE *fp)
相关解释:从指定的文件读取一个字符,该文件必须是以只读或读写的方式打开的。fgetc从fp中读出一个字符并返回这个字符的ASCII码,
若读到文件结束符,则函数返回文件结束标志。
fputc
函数原型:int fputc(int c, FILE *fp)
相关解释:把一个字符写到文件中,若写入成功则返回写入字符的ASCII码,若失败则返回EOF。
fgets
函数原型:char * fgets(char *s, int n, FILE *fp)
相关解释:从fp指向的文件中读取字符,当读到回车符、文件末尾、或满n-1个字符时 就在字符串末尾加上'\0',把他们存放到字符数组s
中后函数返回,若在任何字符读取钱就达到了文件末尾,fgets就返回NULL指针(用于检查是否到达文件尾),否则返回s的首地址
fputs
函数原型:int * fputs(const char *s, FILE *fp)
相关解释:向指定的文件中输入一个字符串,若写入成功则返回0,否则返回EOF。
fread
函数原型:unsigned fread(void *s, unsigned size, unsigned count, FILE *fp)
相关解释:从fp指向的文件中读取二进制数据块到s数组,函数有四个参数
第一个参数s是从文件中读物数据的存放地址,
第二个参数size是要读的字节数的大小,
第三个参数count是要读取多少个size字节的数据,即最多允许读取的数据块的个数,
第四个参数fp为指向要读取的文件的指针
fwrite
函数原型:unsigned fwrite(void *s, unsigned size, unsigned count, FILE *fp)
相关解释:将二进制数据块s写入到fp指向的文件,函数有四个参数
第一个参数s是要向文件写入的数据的存放地址,
第二个参数size是要写的字节数的大小,
第三个参数count是要写多少个size字节的数据,即最多允许写的数据块的个数,
第四个参数fp为指向要写入的文件的指针
返回值1表示写入成功,0表示写入失败
fprintf
函数原型:int fprintf(FILE *fp, const char *format, ...)
相关解释:fprintf函数与printf函数相似,都是格式化输出函数,不同的是printf输出的位置是终端,而fprintf输出的位置是文件
fscanf
函数原型:int fscanf(FILE *fp, const char *format, ...)
相关解释:fscanf函数与scanf函数相似,都是格式化输入函数,不同的是scanf输入的位置是终端,而fscanf输入的位置是文件
[注] 用fprintf和fscanf对文件进行读写,在读入时需要将ASCII码转化成二进制数,在输出时又需将二进制数转化为
字符,时间开销会比较大,因此交换数据比较频繁的情况下最好不要用这两个函数。
fseek
函数原型:int fseek(FILE *fp, long offset, int from)
相关解释:FILE中有一个指向当前位置的位置指针,如果顺序读写文件,每次读取一个字符,读完一个字符之后,位置指针自动移动到下
一个字符。此外我们可以通过函数改变这个指针的位置实现对文件的随机读写,这样的函数就是文件定位函数,fseek就是这
样一个文件定位函数,该函数可以改变文件的位置指针所指向位置,也就是改变下一个读取或写入位置。fseek有三个参数,
第一个参数fp指向要操作文件的指针;
第二个参数offset是位移量,它是以起始点为基点,向前移动的字节数;
第三个参数from为开始定位的起始点。
其中from的取值可以有如下三个(offset可以为负数):
0 SEEK_SET 定位起始点为文件的开始
1 SEEK_CUR 定位起始点为文件位置指针当前的位置
2 SEEK_END 定位起始点为文件的末尾
rewind
函数原型:void rewind(FILE *fp)
相关解释:rewind为文件定位函数,作用是使文件的位置指针重新返回到文件的开头,它同时清除流的错误提示标志。
ftell
函数原型:long ftell(FILE *fp)
相关解释:得到文件指针的当前位置,用相对文件开头的位移量来表示,出错时返回-1L,这个函数可以让你保存一个文件的当前位置,这样
可以在将来再次返回到这个位置。在二进制文件中,返回值就是当前位置到文件头的字节数;在文本文件中,不一定是当前位置到
文件头的字节数,因为有的系统会对行末字符进行转换。
feof
函数原型:int feof(FILE *fp)
相关解释:用于判断文件是否结束,当文件指针指向fp末尾时,函数返回真,否则返回0。
相关测试:
/**
* 复制文件,一次读取一个字符
*/
# include <stdio.h>
# include <stdlib.h>
int main() {
FILE *fpr, *fpw;
FILE * open_file(const char *, const char *);
//打开文件
fpr = open_file("/Users/zhangqingli/Desktop/test.txt", "r");
fpw = open_file("/Users/zhangqingli/Desktop/test2.txt", "w");
//复制原文件内容到目标文件,每次只读取一个字符
char ch;
while ((ch=fgetc(fpr)) != EOF) {
printf("%c", ch);
fputc(ch, fpw);
}
//关闭文件
fclose(fpr);
fclose(fpw);
return 0;
}
//打开一个文件
FILE * open_file(const char *filename, const char *mode) {
FILE * fp = fopen(filename, mode);
if (fp==NULL) {
printf("文件打开失败!\n");
exit(1);
}
return fp;
}
/**
* 复制文件,一次读取或写入一个字符串
*/
# include <stdio.h>
# include <stdlib.h>
# define BUFFER_SIZE 10
int main() {
FILE *fpr, *fpw;
FILE * open_file(const char *, const char *);
//打开文件
fpr = open_file("/Users/zhangqingli/Desktop/test.txt", "r");
fpw = open_file("/Users/zhangqingli/Desktop/test2.txt", "w");
//复制原文件内容到目标文件,一次复制一个字符串
char buffer[BUFFER_SIZE];
while ((fgets(buffer, BUFFER_SIZE, fpr))) {
printf("%s", buffer);
fputs(buffer, fpw);
}
//关闭文件
fclose(fpr);
fclose(fpw);
return 0;
}
//打开一个文件
FILE * open_file(const char *filename, const char *mode) {
FILE * fp = fopen(filename, mode);
if (fp==NULL) {
printf("文件打开失败!\n");
exit(1);
}
return fp;
}
/**
* 从键盘输入3个关于图书的数据,存入文件,再从文件中取出数据,显示到控制台上
*/
# include <stdio.h>
# include <stdlib.h>
# define MIX_SIZE 3
struct book_info {
char name[20];
char author[20];
} book_array[MIX_SIZE];
FILE * open_file(const char *filename, const char *mode);
int save_book_info(const char *filename);
int display_book_info(const char *filename);
int main() {
//初始化图书信息
printf("初始化图书的信息如下\n");
for (int i=0; i<MIX_SIZE; i++) {
printf("请输入图书名称:");
scanf(" %s", book_array[i].name);
printf("请输入图书的作者:");
scanf(" %s", book_array[i].author);
}
//core
const char *filename = "/Users/zhangqingli/Desktop/test.txt";
if (save_book_info(filename)) {
display_book_info(filename);
}
return 0;
}
//打开一个文件
FILE * open_file(const char *filename, const char *mode) {
FILE * fp = fopen(filename, mode);
if (fp==NULL) {
printf("文件打开失败!\n");
exit(1);
}
return fp;
}
//保存图书信息到文件
int save_book_info(const char *filename) {
FILE * fpw;
//打开要写的文件
fpw = open_file(filename, "w");
//将图书信息存入待写入文件
for (int i=0; i<MIX_SIZE; i++) {
int status = (int) fwrite(&book_array[i], sizeof(struct book_info), 1, fpw);
if (status != 1) {
printf("文件写入出错!\n");
return 0;
}
}
//关闭文件
fclose(fpw);
return 1;
}
//从文件读取图书信息到控制台
int display_book_info(const char *filename) {
FILE * fpr;
//打开要读取的文件
fpr = open_file(filename, "r");
//将文件中的数据读出并显示
for (int i=0; i<MIX_SIZE; i++) {
fread(&book_array[i], sizeof(struct book_info), 1, fpr);
printf("%s\t%s\n", book_array[i].name, book_array[i].author);
}
//文件关闭
fclose(fpr);
return 1;
}
/**
* 计算一个文件的大小
*/
# include <stdio.h>
# include <stdlib.h>
FILE * open_file(const char * filename, const char * mode);
long file_size(FILE * fp);
int main() {
FILE * fpr = open_file("/Users/zhangqingli/Desktop/test.txt", "r");
long length = file_size(fpr);
printf("文件的大小为:%ld byte\n", length);
return 0;
}
//打开文件
FILE * open_file(const char * filename, const char * mode) {
FILE * fp;
fp = fopen(filename, mode);
if (fp==NULL) {
printf("文件打开失败!\n");
exit(1);
}
return fp;
}
//计算文件大小
long file_size(FILE * fp) {
long curpos, length;
//计算文件大小
curpos = ftell(fp);
fseek(fp, 0L, SEEK_END);
length = ftell(fp);
//恢复文件指针到当前位置
fseek(fp, curpos, SEEK_SET);
return length;
}