赞
踩
在之前我们使用的无论是结构体还是数组,每次程序运行完后数据就会被清空。如果我们想要在下一次运行程序继续使用之前的值时,就需要重新输入一遍数据,这样的操作很不方便。
如果我们想将数据保存下来,只有当我们自己选择删除数据时,数据才会被清除,这时就可以使用文件。
使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化。
磁盘上的文件是文件。
在C程序设计中,文件一般指的是数据文件和程序文件(从文件功能上分类)
程序运行时读写的数据,比如程序运行需要从中读取数据的文件, 或者输出内容的文件
包括源程序文件(后缀为 .c ) , 目标文件( windows 环境后缀为 .obj ) , 可执行程序( windows 环境后缀为.exe)。
一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含3部分:文件路径+文件名主干+文件后缀
例如: c:\code\test.txt
路径:c:\code\
文件名主干:test
文件后缀: .txt
为了方便起见,文件标识常被称为文件名
FILE * fp;
缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。
缓冲文件系统为每个被使用的文件在内存中开辟一个相应的缓冲区(文件信息区),用来存放文件的有关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是在stdio.h中定义的,取名FILE。
不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。 每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息, 使用者不必关心细节。
上述定义中,f p 是一个指向 FILE 类型数据的指针变量。可以使f p 指向某个文件的文件信息区。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联 的文件
文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。
(因为操作系统对于同时打开的文件数目是有限制的,所以在文件使用结束后必须使用fclose关闭文件,否则会出现意想不到的错误)
可以使用 fopen( ) 函数来创建一个新的文件或者打开一个已有的文件,这个调用会初始化类型 FILE 的一个对象。下面是这个函数调用的原型:
FILE * fopen ( const char * filename, const char * mode );
//fopen(文件路径,文件使用方式);
filename 是字符串,用来命名文件,fopen函数打开filename指定的文件,文件使用方式mode 的值可以是下列值中的一个:
注:fopen 返回一个文件信息区的地址,如果打开失败会返回一个空指针
为了关闭文件,应使用 fclose( ) 函数。
int fclose ( FILE * stream );
如果成功关闭文件,fclose( ) 函数返回零,如果关闭文件时发生错误,函数返回 EOF。这个函数实际上,会清空缓冲区中的数据,关闭文件,并释放用于该文件的所有内存。EOF 是一个定义在头文件 stdio.h 中的常量。
#include <stdio.h>int main (){FILE * pf ;// 打开文件pf = fopen ( "myfile.txt" , "w" );// 文件操作if ( pf != NULL ){/*一系列操作*///关闭文件fclose ( pf );pf = NULL;}return 0 ;}
int fgetc(FILE * stream);
函数功能:从一个以只读或读写方式打开的文件上读字符, 从 stream指定的 流或文件 获取下一个字符(一个无符号字符),并把位置标识符往前移动。
如果读取成功,则返回该字符。
以无符号 char 强制转换为 int 的形式返回读取的字符。
如果到达文件末尾或发生读错误,则返回 EOF。
#include <stdio.h>
int main (){FILE * pf ;// 打开文件pf = fopen ( "myfile.txt" , "w" );// 文件操作int c = 0;int n = 10;if ( pf != NULL ){do
{
c = fgetc(fp);
printf("%c", c);
} while (--n);//关闭文件fclose ( pf );pf = NULL;}return 0 ;}
int fputc(int char, FILE* stream);
函数功能:该函数的功能是把参数 char 指定的字符(一个无符号字符)写入到 stream 指定的流或文件中,并把位置标识符往前移动。
#include <stdio.h>
int main (){FILE * pf ;// 打开文件pf = fopen ( "myfile.txt" , "r" );// 文件操作int c = 0;int n = 10;while (--n){c = fputc(fp);
printf("%c", c);}//关闭文件fclose ( pf );pf = NULL;return 0 ;}
char* fgets(char* str, int n, FILE* stream);
函数功能:该函数从 stream指定的流或文件 中读取字符串并在字符串末尾添加‘\0’,然后存入s,最多读n-1个字符,当读到回车换行符、到达文件尾或读满n-1个字符时,就停止读取。把它存储在 str 所指向的字符串内。
#include <stdio.h>
int main (){FILE * pf ;char str[60];// 打开文件pf = fopen ( "myfile.txt" , "r" );if (pf == NULL){
perror("打开文件时发生错误");
return(-1);
}//文件操作if (fgets(str, 60, stdin) != NULL){
//从标准输入流(键盘)向str中写入内容
puts(str);
}//关闭文件fclose ( pf );pf = NULL;return 0 ;}
int fputs(const char* str, FILE* stream);
函数功能:该函数把字符串写入到 stream指定的流或文件中,但不包括空字符。
#include <stdio.h>
int main (){FILE * pf ;char str[10] = "abcdef";// 打开文件pf = fopen ( "myfile.txt" , "w" );if (pf == NULL){
perror("打开文件时发生错误");
return(-1);
}//文件操作fputs(str, pf); //从str中向 pf 文件写入内容//关闭文件fclose ( pf );pf = NULL;return 0 ;}
int fscanf(FILE* stream, const char* format, ...);
函数功能:从 stream指定的流或文件 读取格式化输入
#include <stdio.h>
#include <stdlib.h>
int main (){FILE * pf ;char str1[10] = "abcdef";char str2[10];// 打开文件pf = fopen ( "myfile.txt" , "w+" );if (pf == NULL){
perror("打开文件时发生错误");
return(-1);
}//文件操作fputs(str1, pf); //从str1中向 pf 文件写入内容rewind(pf);fscanf(pf, "%s" , str2); //pf文件中按格式读取内容,放到str2中puts(str2);//关闭文件fclose ( pf );pf = NULL;return 0 ;}
int fprintf(FILE* stream, const char* format, ...);
函数功能:发送格式化输出到 stream指定的流或文件中。
#include <stdio.h>
#include <stdlib.h>
int main (){FILE * pf ;char str1[10] = "abcdef";char str2[10];// 打开文件pf = fopen ( "myfile.txt" , "w+" );if (pf == NULL){
perror("打开文件时发生错误");
return(-1);
}//文件操作fprintf(pf, "%s" , str1); //从str1中输出内容到 pf 文件rewind(pf);fscanf(pf, "%s" , str2); //pf文件中按格式读取内容,放到str2中puts(str2);//关闭文件fclose ( pf );pf = NULL;return 0 ;}
size_t fread(void* ptr, size_t size, size_t count, FILE * stream);
函数功能:从 stream指定的流或文件 读取数据块到 ptr 所指向的内存中
#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main (){FILE * pf ;char str1[]= "I am a student";
char str2[20];// 打开文件pf = fopen ( "myfile.txt" , "rb+" );if (pf == NULL){
perror("打开文件时发生错误");
return(-1);
}//文件操作fputs(str1, pf);//从str1中输出内容到 pf 文件
rewind(pf);
fread(str2, strlen(str1) + 1,1,pf);//pf文件中按格式读取内容,放到str2中
printf("%s\n", str2);//关闭文件fclose ( pf );pf = NULL;return 0 ;}
size_t fwrite(const void* ptr, size_t size, size_t count, FILE* fp);
函数功能:该函数把ptr指向的内存中的数据块写入到 stream指定的流或文件中
#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main (){FILE * pf ;char str1[]= "I am a student";
char str2[20];// 打开文件pf = fopen ( "myfile.txt" , "rb+" );if (pf == NULL){
perror("打开文件时发生错误");
return(-1);
}//文件操作fwrite(str1, strlen(str1) + 1, 1, fp);//从str1中输出内容到 pf 文件
rewind(pf);
fread(str2, strlen(str1) + 1,1,pf);//pf文件中按格式读取内容,放到str2中
printf("%s\n", str2);//关闭文件fclose ( pf );pf = NULL;return 0 ;}
前面介绍的文件读写函数都是顺序读写,从文件头开始,依次读取各个数据,但有时需要读取文件中间部位的数据,这时从头开始读取就很不方便。C语言提供了一个方法解决这个问题,即移动文件内部的指针,再进行读写。
实现随机读写的关键是要按要求移动位置指针,这称为文件的定位。
void rewind(FILE* stream);
函数功能:将文件位置指针指向文件首字节,即重置位置指针到文件首部
- #include <stdio.h>
- int main()
- {
- int n;
- FILE* pFile;
- char str[27];
- pFile = fopen("myfile.txt", "w+");
- for (n = 'A'; n <= 'Z'; n++)
- fputc(n, pFile);
- rewind(pFile);
- fread(str, 1, 26, pFile);
- fclose(pFile);
- str[26] = '\0';
- puts(str);
- return 0;
- }
int fseek(FILE* stream, long int offset, int whence);
函数功能:将文件位置指针从stream开始移动offset个字节指示下一个要读取的数据的位置
#include <stdio.h>int main (){FILE * pFile ;pFile = fopen ( "myfile.txt" , "wb" );fputs ( "This is an apple." , pFile );fseek ( pFile , 9 , SEEK_SET );fputs ( " sam" , pFile );fclose ( pFile );return 0 ;}
long int ftell(FILE* stream);
函数功能:返回文件指针相对于文件起始位置的字节偏移量
#include <stdio.h>int main (){FILE * pFile ;long size ;pFile = fopen ( "myfile.txt" , "rb" );if ( pFile == NULL ) perror ( "fopen" );else{fseek ( pFile , 0 , SEEK_END );size = ftell ( pFile );fclose ( pFile );printf ( "Size of myfile.txt: %ld bytes.\n" , size );}return 0 ;}
前面讲到:C程序按照文件的功能将文件分成数据文件和程序文件。
而C程序又按照数据的组织形式把文件分为ASCII文件和二进制文件。
在文本文件中,数值型数据的每一位数字作为一个字符以其ASCII码的形式存储,因此,文本文件中的每一位数字都单独占用一个字节的存储空间。
二进制文件则是把整个数字作为一个二进制数存储的,数值的每一位数字不占用单独的存储空间。
有两种方式可能造成文件读取结束:
一种是文件读取到末尾而结束,另一种是读取发生错误(读取失败)而结束。
所以读取结束时,需要判断是读取失败结束,还是读取到文件末尾而结束。
- 文本文件读取是否结束,判断返回值是否为 EOF ( 返回值是数值 ),或者 NULL (返回值是指针),是则读取结束。
例如: fgetc 判断是否为 EOF ,fgets 判断返回值是否为 NULL 。- 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
例如: fread判断返回值是否小于实际要读的个数。
int ferror(FILE* stream);
函数功能:测试给定流 stream 的错误标识符。如果ferror返回值为0(假),表示读取文件未出错。如果返回一个非零值,表示读取文件时发生错误。
int feof(FILE* stream);
函数功能:feof函数是在文件读取结束后,判断文件读取结束的原因的,是读取失败结束,还是遇到文件尾结束。
#include <stdio.h>#include <stdlib.h>int main ( void ){int c ;FILE * pf = fopen ( "myfile.txt" , "r" );if ( ! pf ) {perror ( "fopen" );return EXIT_FAILURE ;}//fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回 EOFwhile (( c = fgetc ( pf )) != EOF ) // 标准 C I/O 读取文件循环{putchar ( c );}// 判断是什么原因结束的if ( ferror ( pf ))puts ( "I/O error when reading" );else if ( feof ( pf ))puts ( "End of file reached successfully" );fclose ( pf );}
#include <stdio.h>
enum { SIZE = 5 };int main ( void ){double a [ SIZE ] = { 1. , 2. , 3. , 4. , 5. };FILE * fp = fopen ( "myfile.txt" , "wb" ); // 必须用二进制模式fwrite ( a , sizeof * a , SIZE , fp ); // 写 double 的数组fclose ( fp );double b [ SIZE ];fp = fopen ( "myfile.txt" , "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 ( "%.2f " , b [ n ]);putchar ( '\n' );} else { // error handlingif ( feof ( fp )) //判断是否是读到文件末尾而结printf ( "Error reading test.bin: unexpected end of file\n" );else if ( ferror ( fp )) { //判断是否是读取错误而结束perror ( "Error reading test.bin" );}}fclose ( fp );}
缓冲文件系统是指:C语言为了提高数据的输入/输出的速度,在缓冲文件系统中,给正在使用的每一个文件建立一个“文件缓冲区”。
建立文件缓冲区虽然可以提高I/O的性能,但也有一些副作用,例如在缓冲区内容还未写入磁盘时,计算机突然死机或掉电,数据就会丢失,永远也找不回来,再如缓冲区被写入无用的数据时,如果不清除,其后的文件读操作都首先要读取这些无用的数据。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。