/* 倒序显示文件的内容 */
#include <stdio.h>
#include <stdlib.h>
#define SLEN 81
int main(void) {
char file[SLEN];
char ch;
FILE *fp;
long count, last;
puts("Enter the name of the file to be processed:");
scanf("%80s", file);
if ((fp = fopen(file, "rb")) == NULL){ /* 只读模式,二进制读取 */
printf("reverse can't open %s\n", file);
exit(EXIT_FAILURE);
}
fseek(fp, 0L, SEEK_END); /* 定位到文件末尾 */
last = ftell(fp);
for (count = 1L; count <= last; count++) {
fseek(fp, -count, SEEK_END); /* 回退 */
ch = getc(fp);
if (ch != CTRL_Z && ch != '\r') /* MS-DOS下'\032'表示结束符CTRL_Z的ASCII码 ,可以#define宏定义之*/
putchar(ch);
}
putchar('\n');
fclose(fp);
return 0;
}
Debug目录下事先新建了文件Cluv且写入了正序的字符串"I think than I shall ...... one in C."。
Enter the name of the file to be processed:
|Cluv
.C ni eno naht ylevol erom margorp a
ees reven llahs I taht kniht I
我们设计的程序清单在UNIX和MS-DOS环境下都可以运行。UNIX只有一种文件格式,所以不需要进行特殊的转换。然而MS-DOS要格外注意。许多MS-DOS编辑器都用Ctrl+Z标记文本文件的结尾。以文本模式打开这样的文件时,C 能识别这个作为文件结尾标记的字符。但是,以二进制模式打开相同的文件时,Ctrl+Z字符被看作是文件中的一个字符,而实际的文件结尾符在该字符的后面。文件结尾符可能紧跟在Ctrl+Z字符后面,或者文件中可能用空字符填充,使该文件的大小是256的倍数。在DOS环境下不会打印空字符,以上程序清单中就包含了防止打印Ctrl+Z字符的代码。
二进制模式和文本模式的另一个不同之处是:MS-DOS用\r\n组合表示文本文件换行。以文本模式打开相同的文件时,C程序把\r\n看成\n。但是,以二进制模式打开该文件时,程序能看见这两个字符。因此,程序清单中还包含了不打印\r的代码。通常,UNIX文本文件既没有Ctrl+Z,也没有\r,所以这部分代码不会影响大部分UNIX文本文件。ftell()函数在文本模式和二进制模式中的工作方式不同。许多系统的文本文件格式与UNIX的模型有很大不同,导致从文件开始处统计的字节数成为一个毫无意义的值。ANSI C规定,对于文本模式,ftell()返回的值可以作为fseek()的第2个参数。对于MS-DOS,ftell()返回的值把\r\n当作一个字节计数。
可移植性:
理论上,fseek()和ftell()应该符合UNIX模型。但是,不同系统存在着差异,有时确实无法做到与UNIX模型一致。因此,ANSI对这些函数降低了要求。下面是一些限制。
在二进制模式中,实现不必支持SEEK_END模式。因此无法保证以上程序清单的可移植性。移植性更高的方法是逐字节读取整个文件直到文件末尾。C 预处理器的条件编译指令(第 16 章介绍)提供了一种系统方法来处理这种情况。
在文本模式中,只有以下调用能保证其相应的行为。不过,许多常见的环境都支持更多的行为。
网友评论