在下面的程序中, 我们将通过键盘键入的字符依次写入demo.txt中.
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *fp;/* 定义文件指针fp */
char ch;
if((fp = fopen("C:\\Users\\surface\\Desktop\\demo.txt", "w")) == NULL)/* 以只写的方式打开文件 */
{
/* 打开文件时发生错误 */
printf("Failure to open demo.txt!\n");
exit(0);
}
ch = getchar();
while(ch != '\n')
{
fputc(ch, fp);/* 将刚刚输入的字符写入fp指向的文件中 */
ch = getchar();
}
if(fclose(fp) == 0)
{
/* 文件关闭成功, fclose()返回0 */
printf("Success for writing the string to file demo.txt.\n");
}
else
{
/* 文件关闭失败, fclose()返回EOF(-1) */
exit(0);
}
return 0;
}
[运行结果]
在程序运行前, 指定目录(桌面)下无demo.txt文件, 接下来运行上述程序.
此时切回桌面, 发现demo.txt文件已自动创建.
接着我们打开文件, 查看文件中的内容.
可以发现, 文件中的内容就是我们刚才从键盘输入的内容.
随后我们再次运行上述程序.
在程序运行后, 再次查看demo.txt中的内容.
可以发现, 之前文件中的内容已被清除, 取而代之的是我们刚刚通过键盘键入的信息: 这也是用fopen函数以w模式打开文件的特点.
如果我们希望将demo.txt文件中的内容通过屏幕显示出来, 则需要借助于fgetc函数实现.
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *fp;/* 定义文件指针fp */
char ch;
if((fp = fopen("C:\\Users\\surface\\Desktop\\demo1.txt", "r")) == NULL)/* 以只读的方式打开文件 */
{
/* 打开文件时发生错误 */
printf("Failure to open demo.txt!\n");
exit(0);
}
ch = fgetc(fp);
while(ch != EOF)/* 只要从文件中读取的字符不是文件结束符EOF, 循环就继续下去 */
{
putchar(ch);/* 将刚刚从文件中读取的字符输出到屏幕上 */
ch = fgetc(fp);/* 从文件中读取下一字符, 并保存在ch变量中 */
}
if(fclose(fp) == 0)
{
/* 文件关闭成功, fclose()返回0 */
printf("\nSuccess for reading the string from file demo.txt.\n");
}
else
{
/* 文件关闭失败, fclose()返回EOF(-1) */
exit(0);
}
return 0;
}
运行上面的程序.
可以看出, 文件demo.txt中的内容成功地出现在屏幕上.
如果我们将demo.txt改为demo1.txt(此文件不存在), 程序还会自动生成demo1.txt吗?
此时, 程序打开demo1.txt文件失败, 这也说明用fopen函数以"r"模式打开文件时, 若指定文件不存在, 程序不会自动创建该文件.
除了通过判断读出的字符是否为文件结束符EOF外, 另外还可以调用C语言为我们提供的一个标准库函数来判断是否已经定位到文件尾: 这个库函数就是feof, 该函数的功能就是用于检测是否已经到达文件尾. 当检测到文件尾时, 返回非零值; 否则返回0.
下面对上述程序略作修改, 即将while循环的判断条件改为 feof(fp) == 0, 以此代替上述程序中的 ch != EOF.
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *fp;/* 定义文件指针fp */
char ch;
if((fp = fopen("C:\\Users\\surface\\Desktop\\demo.txt", "r")) == NULL)/* 以只读的方式打开文件 */
{
/* 打开文件时发生错误 */
printf("Failure to open demo.txt!\n");
exit(0);
}
ch = fgetc(fp);
while(feof(fp) == 0)/* 只要从文件中读取的字符不是文件结束符EOF, 循环就继续下去 */
{
putchar(ch);/* 将刚刚从文件中读取的字符输出到屏幕上 */
ch = fgetc(fp);/* 从文件中读取下一字符, 并保存在ch变量中 */
}
if(fclose(fp) == 0)
{
/* 文件关闭成功, fclose()返回0 */
printf("\nSuccess for reading the string from file demo.txt.\n");
}
else
{
/* 文件关闭失败, fclose()返回EOF(-1) */
exit(0);
}
return 0;
}
接下来我们如下图示修改while循环体内的语句, 运行程序, 查看运行结果是否正确.
从程序的运行结果来看, 似乎一切都很正常.
接着, 我们将while循环体内的putchar函数改为printf函数, 并附加输出每个字符在文件中的位置, 看看运行结果会有什么不同.
可以发现, 输出结果较之前的程序多了一个输出, 那么这种现象背后的原因是什么呢?
在上面的程序中, 最后一次循环用fgetc函数从文件中读出的字符实际上就是文件结束符EOF(ASCII码值为-1), 这样一来程序的输出多出一行也就并不奇怪了. 这说明feof函数只有当读到文件结束符时, 才能判断出到达文件尾: feof函数总是在读完文件所有内容后, 再执行一次读文件操作, 将文件结束符EOF读走, 才能返回非0值.
针对上面将文件结束符也输出的问题, 可以像下面这样解决.
[解决方案1]
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *fp;/* 定义文件指针fp */
char ch;
long pos;
if((fp = fopen("C:\\Users\\surface\\Desktop\\demo.txt", "r")) == NULL)/* 以只读的方式打开文件 */
{
/* 打开文件时发生错误 */
printf("Failure to open demo.txt!\n");
exit(0);
}
pos = ftell(fp);
ch = fgetc(fp);
while(feof(fp) == 0)/* 只要从文件中读取的字符不是文件结束符EOF, 循环就继续下去 */
{
printf("%c, %ld\n", ch, pos);
pos = ftell(fp);
ch = fgetc(fp);/* 从文件中读取下一字符, 并保存在ch变量中 */
}
if(fclose(fp) == 0)
{
/* 文件关闭成功, fclose()返回0 */
printf("\nSuccess for reading the string from file demo.txt.\n");
}
else
{
/* 文件关闭失败, fclose()返回EOF(-1) */
exit(0);
}
return 0;
}
[解决方案2]
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *fp;/* 定义文件指针fp */
char ch;
long pos;
if((fp = fopen("C:\\Users\\surface\\Desktop\\demo.txt", "r")) == NULL)/* 以只读的方式打开文件 */
{
/* 打开文件时发生错误 */
printf("Failure to open demo.txt!\n");
exit(0);
}
pos = ftell(fp);
ch = fgetc(fp);
while(ch != EOF)/* 只要从文件中读取的字符不是文件结束符EOF, 循环就继续下去 */
{
printf("%c, %ld\n", ch, pos);
pos = ftell(fp);
ch = fgetc(fp);/* 从文件中读取下一字符, 并保存在ch变量中 */
}
if(fclose(fp) == 0)
{
/* 文件关闭成功, fclose()返回0 */
printf("\nSuccess for reading the string from file demo.txt.\n");
}
else
{
/* 文件关闭失败, fclose()返回EOF(-1) */
exit(0);
}
return 0;
}
可对解决方案2中蓝色区域做出精简, 精简后的程序如下示.
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *fp;/* 定义文件指针fp */
char ch;
long pos;
if((fp = fopen("C:\\Users\\surface\\Desktop\\demo.txt", "r")) == NULL)/* 以只读的方式打开文件 */
{
/* 打开文件时发生错误 */
printf("Failure to open demo.txt!\n");
exit(0);
}
pos = ftell(fp);
while((ch = fgetc(fp)) != EOF)/* 只要从文件中读取的字符不是文件结束符EOF, 循环就继续下去 */
{
printf("%c, %ld\n", ch, pos);
pos = ftell(fp);
}
if(fclose(fp) == 0)
{
/* 文件关闭成功, fclose()返回0 */
printf("\nSuccess for reading the string from file demo.txt.\n");
}
else
{
/* 文件关闭失败, fclose()返回EOF(-1) */
exit(0);
}
return 0;
}
接下来我们再来探讨一个问题, 当读到文件尾或发生读取错误时, fgetc函数均返回EOF, 所以当fgetc函数返回EOF时, 我们并不能确定导致这一现象发生的原因. 由此可见, 用EOF来判断是否到达文件尾的方法并不是一种很严谨的方法, 即我们不能用判断fgetc函数是否返回EOF来完全代替feof函数的作用(最好还是用feof函数来判断是否已经到达文件尾).
检测是否发生文件读取错误的函数是ferror(), 出错时ferror函数返回非0值, 否则返回0.
最后, 给出具备文件读取检错功能的程序实现.
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *fp;/* 定义文件指针fp */
char ch;
long pos;
if((fp = fopen("C:\\Users\\surface\\Desktop\\demo.txt", "r")) == NULL)/* 以只读的方式打开文件 */
{
/* 打开文件时发生错误 */
printf("Failure to open demo.txt!\n");
exit(0);
}
pos = ftell(fp);
while((ch = fgetc(fp)) != EOF)/* 只要从文件中读取的字符不是文件结束符EOF, 循环就继续下去 */
{
if(ferror(fp) != 0)
{
/* 发生文件读取错误 */
printf("Error on file.\n");
exit(0);
}
printf("%c, %ld\n", ch, pos);
pos = ftell(fp);
}
if(fclose(fp) == 0)
{
/* 文件关闭成功, fclose()返回0 */
printf("\nSuccess for reading the string from file demo.txt.\n");
}
else
{
/* 文件关闭失败, fclose()返回EOF(-1) */
exit(0);
}
return 0;
}