学习C – C文件
C程序员使用指针来管理用于读取和写入数据的流。
流只是文件或硬件设备,如显示器或打印机。
要指向并管理C中的文件流,请使用名为FILE的数据结构。
类型FILE的指针就像任何其他变量一样创建。
#include <stdio.h> int main(void) { //create 3 file pointers FILE *pRead; FILE *pWrite; FILE *pAppend; return 0; } //end main
上面的代码创建了三个名为pRead,pWrite和pAppend的FILE指针变量。
每个FILE指针可以打开和管理单独的数据文件。
打开和关闭文件
文件处理的基本组件是打开,处理和关闭数据文件。
打开一个文件应该有错误检查和/或处理。
未能测试文件打开的结果将导致不必要的程序结果。
要打开数据文件,请使用标准输入/输出库函数fopen()。
fopen()函数返回一个指向FILE指针的FILE指针。
#include <stdio.h>
main()
{
FILE *pRead;
pRead = fopen("file1.dat", "r");
} //end main
该程序使用fopen()函数以只读方式打开名为file1.dat的数据文件。
fopen()函数返回一个FILE指针返回到pRead变量。
fopen()函数有两个参数:文件名,第二个参数告诉fopen()如何打开文件。
下表列出了使用fopen()打开文本文件的几个常用选项。
模式 | 描述 |
---|---|
r | 打开文件进行阅读 |
w | 创建写入文件; 丢弃任何以前的数据 |
a | 写入文件结尾(追加) |
上面的代码生成以下结果。
打开文件示例
打开文件后,应确保文件指针成功返回。
要测试fopen()的返回值,请测试条件中的NULL值,如下所示。
#include <stdio.h>
main()
{
FILE *pRead;
pRead = fopen("file1.dat", "r");
if ( pRead == NULL )
printf("\nFile cannot be opened\n");
else
printf("\nFile opened for reading\n");
} //end main
以下条件
if ( pRead == NULL )
可以缩短下一个条件。
if ( pRead )
如果pRead返回非NULL,则if条件为true。如果pRead返回NULL,则该条件为false。
成功打开和处理文件后,应使用函数fclose()关闭文件。
fclose()函数使用FILE指针来刷新流并关闭文件。
fclose()函数将FILE指针名称作为参数。
fclose(pRead);
上面的代码生成以下结果。
读取数据
以下代码显示如何使用函数fscanf()和feof()读取文件的内容并检查文件的EOF(文件结尾)标记。
以下程序读取名为.dat的数据文件,直到读取文件结束标记为止。
#include <stdio.h>
main()
{
FILE *pRead;
char name[10];
pRead = fopen("names.dat", "r");
if ( pRead == NULL )
printf("\nFile cannot be opened\n");
else
printf("\nContents of names.dat\n\n");
fscanf(pRead, "%s", name);
while ( !feof(pRead) ) {
printf("%s\n", name);
fscanf(pRead, "%s", name);
} //end loop
} //end main
在成功打开names.dat之后,我使用fscanf()函数来读取文件中的一个字段。
fscanf()函数与scanf()函数类似,但与FILE流有关。
它有三个参数:一个FILE指针,一个数据类型和一个变量来存储检索到的值。
读取记录后,printf()函数显示文件中的数据。
要读取多个记录,请使用可以读取所有记录的循环,直到满足条件。
要读取所有记录,直到满足文件结尾,请使用feof()函数。
使用非运算符(!),可以将FILE指针传递给feof()函数并循环,直到达到文件结尾标记时函数返回非零值。
通过向第二个参数提供记录中每个字段的一系列类型说明符,fscanf()也可以读取包含多个字段的记录。
例如,下一个fscanf()函数希望读取两个名为name和hobby的字符串。
fscanf(pRead, "%s%s", name, hobby);
%s类型说明符将读取一系列字符,直到找到空白,包括空白,新行或选项卡。
fscanf()函数的其他有效类型说明符列在表11.3中。
类型 | 描述 |
---|---|
c | 单字符 |
d | 十进制整数 |
e,E,f,g,G | 浮点 |
o | 八进制整数 |
s | 字符串 |
u | 无符号十进制整数 |
x,X | 十六进制整数 |
上面的代码生成以下结果。
多个字段示例
以下代码显示如何读取多个字段。
#include <stdio.h>
main()
{
FILE *pRead;
char name[10];
char hobby[15];
pRead = fopen("hobbies.dat", "r");
if ( pRead == NULL )
printf("\nFile cannot be opened\n");
else
printf("\nName\tHobby\n\n");
fscanf(pRead, "%s%s", name, hobby);
while ( !feof(pRead) ) {
printf("%s\t%s\n", name, hobby);
fscanf(pRead, "%s%s", name, hobby);
} //end loop
} //end main
上面的代码生成以下结果。
写数据
fprintf()函数接收FILE指针,数据类型列表以及将数据写入数据文件的值列表。
例子
通过用记录分隔记录中的每个字段,我可以使用以下程序轻松地读取相同的记录。
#include <stdio.h>
main()
{
FILE *pRead;
char fName[20];
char lName[20];
char id[15];
float gpa;
pRead = fopen("students.dat", "r");
if ( pRead == NULL )
printf("\nFile not opened\n");
else {
//print heading
printf("\nName\t\tID\t\tGPA\n\n");
//read field information from data file and store in variables
fscanf(pRead, "%s%s%s%f", fName, lName, id, &gpa);
//print variable data to standard output
printf("%s %s\t%s\t%.2f\n", fName, lName, id, gpa);
fclose(pRead);
} //end if
} //end main
使用带有w参数值的fopen()打开数据文件将会擦除文件中存储的任何以前的数据。
使用a属性在文件末尾附加数据。
上面的代码生成以下结果。
附加数据
将信息附加到数据文件中,包括使用fopen()中的一个属性打开一个写入文件,并将数据写入现有文件的末尾。
但是,如果该文件不存在,则会按照fopen()语句中的指定创建一个新的数据文件。
以下代码演示将记录附加到现有数据文件。
#include <stdio.h>
void readData(void);
main()
{
FILE *pWrite;
char name[10];
char hobby[15];
printf("\nCurrent file contents:\n");
readData();
printf("\nEnter a new name and hobby: ");
scanf("%s%s", name, hobby);
//open data file for append
pWrite = fopen("hobbies.dat", "a");
if ( pWrite == NULL )
printf("\nFile cannot be opened\n");
else {
//append record information to data file
fprintf(pWrite, "%s %s\n", name, hobby);
fclose(pWrite);
readData();
} //end if
} //end main
void readData(void)
{
FILE *pRead;
char name[10];
char hobby[15];
//open data file for read access only
pRead = fopen("hobbies.dat", "r");
if ( pRead == NULL )
printf("\nFile cannot be opened\n");
else {
printf("\nName\tHobby\n\n");
fscanf(pRead, "%s%s", name, hobby);
//read records from data file until end of file is reached
while ( !feof(pRead) ) {
printf("%s\t%s\n", name, hobby);
fscanf(pRead, "%s%s", name, hobby);
}
}
fclose(pRead);
} //end readData
上面的代码生成以下结果。
例2
以下代码使用goto和一些新功能(perror()和exit())来构建文件I/O程序中的错误处理。
#include <stdio.h>
#include <stdlib.h>
main() {
FILE *pRead;
char name[10];
char hobby[15];
pRead = fopen("hobbies.dat", "r");
if ( pRead == NULL )
goto ErrorHandler;
else {
printf("\nName\tHobby\n\n");
fscanf(pRead, "%s%s", name, hobby);
while ( !feof(pRead) ) {
printf("%s\t%s\n", name, hobby);
fscanf(pRead, "%s%s", name, hobby);
} //end loop
} // end if
exit(EXIT_SUCCESS); //exit program normally
ErrorHandler:
perror("The following error occurred");
exit(EXIT_FAILURE); //exit program with error
} //end main
exit()函数(<stdlib.h>库的一部分)终止程序,就好像它正常退出一样。
如下所示,exit()函数对于想要在遇到文件I/O(输入/输出)错误时终止程序的程序员很常见。
exit(EXIT_SUCCESS); //exit program normally
或
exit(EXIT_FAILURE); //exit program with error
exit()函数接受一个参数,一个常量为EXIT_SUCCESS或EXIT_FAILURE,两者都分别为成功或失败返回预定义的值。
perror()函数向标准输出发送消息,描述遇到的最后一个错误。
perror()函数采用单个字符串参数,首先打印,后跟冒号和空白,然后系统生成错误消息和新行。
perror("The following error occurred");
上面的代码生成以下结果。