文件
C程序,将文件看做是连续字节序列,其中每个字节都可以单独读取.这个与UNIX环境中的文件结构是一致的.但ANSI C为了与其他的OS环境兼容(比如Windows),提供了两种文件视图: 文本视图和二进制视图.
文本视图和二进制视图
二进制视图中,文件中的每个字节都可以为程序访问.但文本视图中,程序中看到的内容与文件的内容可能不同.
例如MS-DOS文本文件用"\r\n"来表示行尾; Macintosh文本文件中用"\r"表示行尾; C程序使用"\n"表示行尾. So,如果C程序以文本视图模式处理一个MS-DOS文本文件,在读取文件时,就会将"\r\n"转换为"\n",在写入文件时,就会将"\n"转换为"\r\n". Macintosh同理.
说白了,两种视图的实现是一样的,只是在处理行尾或处理文件结尾时有点不同而已.采用某种视图打开文件时,注意一下就是了.
文件结尾和换行
文件读取数据的程序需要在达到文件结尾时停止.当到达文件结尾时,"getc()"函数会返回一个特殊值EOF.所以C程序只有在读取超出文件结尾后,才会发现文件的结尾.
为了避免读取空文件带来的问题,应该对文件输入使用入口条件循环(使用while或for,避免使用do...while)如下设计:
int ch; // Watching EOF
FILE* fp;
fp = fopen ("_FileName", "_Mode");
ch = getc (fp);
while (ch != EOF)
{
putchar (ch);
ch = getc (fp);
}
上面的例子可以看做是一个框架,来进行文件结尾的判断.但ANSI C的两种模式,对于文件结尾有不同的解释.
如果文件以文本模式打开,C可以认出EOF标志文件结尾.如果以二进制模式打开,就会把EOF当做是文件中的一个字符.真正的文件结尾还在后面.文件的结尾,可能紧跟着EOF,当然,也可能用空字符填充文件使其大小为256(或其他数)的倍数.在DOS下不打印空字符.程序中包含了防止程序打印EOF字符的代码.
MS-DOS的文本文件用二进制模式和文本模式打开,C程序将看到下面的内容:
二进制模式打开文件C程序看到的内容: line1\r\n line2\r\n line3\r\n ^Z | 文本模式打开文件C程序看到的内容: line1\n line2\n line3\n ^Z |
例子 : 逆序输出一个文件内容
#include <stdio.h>
#include <stdlib.h>
#define MAC
#define CNTL_Z '\032' /* DOS Text File End Of File Flag */
#define SLEN 50
#define PATH
int main (void)
{
unsigned char file[SLEN];
unsigned char ch;
FILE* fp;
unsigned long count;
unsigned long last;
puts ("Enter Name Of File To Be Processed : ");
gets (file);
if ((fp = fopen (file, "rb")) == NULL)
{
printf ("Reverse Can't Open %s .\n", file);
exit (1);
}
fseek (fp, 0L, SEEK_END); /* Locate To End Of File */
last = ftell (fp);
for (count = 1L; count <= last; count++)
{
fseek (fp, -count, SEEK_END); /* Back 1 Byte */
ch = getc (fp);
if (ch != CNTL_Z && ch != '\r')
{
putchar (ch);
}
#if defined MAC || defined WIN32
/* Macintosh || Windows */
if (ch == '\r')
{
putchar ('\n');
}
else
{
putchar (ch);
}
#endif
putchar ('\n');
fclose (fp);
return 0;
}
}