关于C之文件结尾EOF与二进制文件换行符 您所在的位置:网站首页 linux在文件末尾添加换行符号 关于C之文件结尾EOF与二进制文件换行符

关于C之文件结尾EOF与二进制文件换行符

2024-06-12 07:57| 来源: 网络整理| 查看: 265

文件结尾:

计算机操作系统要以某种方式判断文件的开始和结束。 检测文件结尾的一种方法是, 在文件末尾放一个特殊的字符标记文件尾。

CP/M、 IBMDOS和MS-DOS的文本文件曾经用过这种方法。 如今, 这些操作系统可以使用内嵌的Ctrl+Z字符来标记文件结尾。 这曾经是操作系统使用的唯一标记,不过现在有一些其他的选择, 例如记录文件的大小。 所以现代的文本文件不一定有嵌入的Ctrl+Z, 但是如果有, 该操作系统会将其视为一个文件结尾标记。 

下图显示了这种方法(一个带文件结尾标记的文件,现代的文本文件不一定嵌入有^Z,这里只是演示):

操作系统使用的另一种方法是储存文件大小的信息。 如果文件有3000字节, 程序在读到3000字节时便达到文件的末尾。 MS-DOS 及其相关系统使用这种方法处理二进制文件, 因为用这种方法可以在文件中储存所有的字符,包括Ctrl+Z。 新版的DOS也使用这种方法处理文本文件。 UNIX使用这种方法处理所有的文件。

无论操作系统实际使用何种方法检测文件结尾,在C语言中,用getchar()读取文件检测到文件结尾时将返回一个特殊的值,即EOF( end of file的缩写)。scanf()函数检测到文件结尾时也返回EOF。

通常, EOF定义在stdio.h文件中:#define EOF (-1)

为什么是-1?因为getchar()函数的返回值通常都介于0~127,这些值对应标准字符集。但是,如果系统能识别扩展字符集,该函数的返回值可能在0~255之间。无论哪种情况,-1都不对应任何字符,所以,该值可用于标记文件结尾。

如果包含stdio.h文件,并使用EOF符号,就不必担心EOF值不同的问题。这里关键要理解EOF是一个值,标志着检测到文件结尾, 并不是在文件中找得到的符号。

#include int main(void) { int ch; while ((ch = getchar()) != EOF) putchar(ch); return 0; }

以上程序表示:重复输入,直到文件结尾。

输入回车仅代表输入了一个换行符 !=EOF,输入-1也正常打印,所以输入回车或EOF对应的值都是结束不了程序的,因为-1也好EOF也好,回车符也好,都仅仅只是输入了相应的字符而已,并不是控制命令。对于Mac OS系统来说,输入ctrl+d即发送EOF,这时getchar()==EOF了,程序才结束终止。在PC中,要按下ctrl+z。

使用该程序进行键盘输入, 要设法输入EOF字符。 不能只输入字符EOF, 也不能只输入-1( 输入-1会传送两个字符: 一个连字符和一个数字1) 。 正确的方法是, 必须找出当前系统的要求。 例如, 在大多数UNIX和Linux系统中, 在一行开始处按下Ctrl+D会传输文件结尾信号。 许多微型计算机系统都把一行开始处的Ctrl+Z识别为文件结尾信号, 一些系统把任意位置的Ctrl+Z解释成文件结尾信号。

下面结出一个打开一个文件并显示该文件的例子:

#include #include // 为了使用exit() int main() { int ch; FILE* fp; char fname[50]; // 储存文件名 printf("Enter the name of the file: "); scanf("%s", fname); fp = fopen(fname, "r"); // 打开待读取文件(待读取的文件应该与可执行文件位于同一目录) if (fp == NULL) { // 如果失败 printf("Failed to open file. Bye\n"); exit(1); // 退出程序 } while ((ch = getc(fp)) != EOF) // getc(fp)从打开的文件中获取一个字符 putchar(ch); fclose(fp); // 关闭文件 return 0; }

换行符:

在文本处理中, CR, LF, CRLF是不同操作系统上使用的换行符.  Windows/Dos         :采用回车+换行(CRLF)表示下一行.  OS X/UNIX/Linux   :采用换行符LF表示下一行.  Mac OS 9及以前    :采用回车符CR表示下一行.  CR用符号'\r'表示, 十进制ASCII代码是13, 十六进制代码为0x0D;  LF用符号'\n'表示, 十进制ASCII代码是10, 十六制为0x0A.  所有Windows平台上换行在文本文件中是使用 0D 0A 两个字节表示, 而UNIX和OS X平台上换行则是使用0A一个字节表示,在早期Mac OS 9平台上换行则是使用0D一个字节表示。 

一般操作系统上的运行库会自动决定文本文件的换行格式。如一个程序在Windows上运行就生成CR LF换行格式的文本文件,而在OS X/Unix/Linux上运行就生成LF格式换行的文本文件。

在Mac OS系统下,输入纯文件内容如下:

Hello World My doc!

然后用16进制工具打开此文件:

通过ASCII码表我们可以确定16进制的64对应字符'd',16进制的21对应字符'!',16进制的0A对应换行LF。并没有文件结尾符。

在Windows系统下,用16进制工具打开同样的文件:

通过ASCII码表我们可以确定16进制的0D 0A对应字符CR LF。其他与Mac OS系统相同。也并没有文件结尾符^Z。就像上面所述,用储存文件大小的信息来判断结尾了,这样可以存储所有字符,当然包括^Z了。

如果用16进制打开一个.RTF、.docx这样的同样有着纯文件内容的文件,得到的是很大一串的16进制码,并且好像找不到原来的文本内容了。一个mydoc.docx文件,同样的内容文本,转换结果一团乱麻(里面含有格式、字体、字号、颜色、对齐方式等等大量描述的内容),如下:

在Mac上运行如下代码:(打开一个桌面上的内容为“abcdef"的文本text.rtf文件,输出所有字符)

scanf("%s", fname); fp = fopen(fname, "r"); // open file for reading while ((ch = getc(fp)) != EOF) // gets a character from the open file putchar(ch);

运行结果如下:

                                 标志换行Windows/DosOS X Unix Linux ...\r\n ()\n ()

假设有如下代码:

/* 功能:逆序输出文件中的内容 */ char ch; while(...) {// 注:此时fp已经重定向到了文件的结尾 ch = getc(fp);// fp是以二进制模式"rb"打开的文件对应的指针 if(...) putchar(ch); }

从文件指针FILE * fp所指向的文件中依次读取字符,这时就要判断文件结尾的问题,if语句内容可以如下:

//#define CTRL_Z '\032' if (ch != CTRL_Z && ch != '\r') putchar(ch);

Ctrl+Z对应于ASCII中^Z,对应字符为'\032'(八进制)。详见:关于ASCII码与转义字符

在Windows下最常见就是:在读出时,将回车符'\r\n'解释成'\n';在写入时,将'\n'解释成'\r\n'。

因为本例中getc()是从二进制文件以字符方式读取的,不同操作系统它的换行符不一样,由于是逆序输出文件中的内容,为了兼容,先判断最后一个字符是否为结尾字符,如果是,因为是系统自动生成的,对内容无影响,不打印输出。而对于Windows系统,'\r\n'才代表换行,也是系统自动生成的,我们只需要换行的意义就行,所以过滤掉'\r'保留'\n',这样对内容显示也无任何影响。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有