文件中的最后一个字符是什么?


19

我刚刚阅读了“在文件末尾删除换行符”的答案,每个人都说要删除最后一个字符。我的问题是,最后一个不是eof角色吗?



1
@SorenBjornstad我还想补充一点,当Unix文本文件的末尾有换行符时,它就在那里,因为它终止了最后一行。空文本文件的末尾没有换行符:它是一个零字符序列。
哈兹

3
为了稍微讲究技巧,CPM和DOS确实使用^ Z作为EOF字符,并且您有时仍可能会遇到以^ Z结尾的文件。
爱德华·福尔克

Answers:


13

文件没有以文件结尾字符结尾,因为前面的答案正确指出。但我认为答案和评论包含一些不正确之处,值得指出:

  • ASCII字符集不包含确切的EOF字符。有几个“结束”控制字符:文本结尾(3),传输结尾(4),传输块结尾(23),媒体结尾(25)。文件分隔符(28)可能最接近EOF字符。代码26是“替代”,不是EOF。

  • Ctrl- D仅与终端输入关联。例如,该命令 cat filea fileb filec > outfile不包含Ctrl- D。顺便说一句,您可以使用命令将终端EOF字符更改为Ctrl- 以外的其他字符。Dstty

  • 严格来说,Ctrl- D(或您更改的任何内容)不是EOF密钥代码。它所做的是使read系统调用返回带有可用输入的内容,就像按return使读取的系统调用将一行字符返回给调用者一样。按照惯例,读取的系统调用的返回值为零(即读取的零字符)表示文件状态结束。但是,输入文件不会自动关闭,并且,如果输入来自终端,则不会处于“文件末尾”状态。您可以编写一个程序,即使在“文件结束”之后,该程序也可以继续从终端读取数据,并且读取调用对于下一个输入行可以返回非零值。

  • 如果已经在行上写入了某些输入,则按Ctrl- 可以看到eof和eol字符之间的类比D。例如,如果您写入“ abc”,然后按press Ctrl- Dread调用将返回,这一次返回值为3,并且将“ abc”存储在作为参数传递的缓冲区中。由于read不返回0,因此上述约定不会将其解释为EOF条件。类似地,按回车键将使读调用返回整个输入行(包括换行符)。您可以使用以下cat命令进行尝试:在行上写一些字符,然后按Ctrl- D。您会看到字符回显给您,并cat等待更多输入。

  • 以上所有内容仅适用于终端处于“ cooked”模式(与“ raw”模式相对)的情况,在该模式中,线路输入处理被最小化。在原始模式下,Ctrl-D字符实际上会传递到输入缓冲区。


19

ASCII控制字符具有1960年代的定义(实际上是在您可能认为是网络之前)。并非所有这些控制字符都以当时为电信设备定义的方式使用。

在类似Unix的系统上,不需要EOF字符。没有使用。系统可以告诉应用程序文件中有多少字节:

  • 在某些其他系统(在VMS,DOS,Windows中可见)上,control-Z可能充当文件结尾标记,因为在较旧版本中,系统无法告诉某些应用程序文件中有多少字节。

    对于VMS,限制是由于C运行时的工作方式引起的。汇编语言应用程序可以(并且确实)获得正确的文件大小。

  • 外壳程序中的Unix系统通常使用control-D来告知应用程序已到达输入(文件)的末尾,但是control-D未存储在文件中。

在C中,EOF故意-1表示它不是有效字符。EOF检测到文件结束条件时返回标准I / O ,而不是特殊字符。

顺便说一句,文件不必以换行符(ASCII 换行符)结尾。文本编辑器可以处理都是可打印文本但没有尾随换行符的文件。


8
POSIX将文本文件定义为包含一系列行的文件,然后将每一行定义为一系列非换行字符,后跟一个换行。因此,以0x0A结尾的文件不是符合条件的文本文件。
达米安·耶里克

2
我意识到这一点,这就是为什么我指出文本编辑器可以工作的原因。(二进制文件没有这样的约束)。
托马斯·迪基

确实值得一提的是,打算作为没有尾随换行符的文本处理的文件仍然可以说是不好的形式(即使典型的文本编辑器已被编码为可补偿此类文件),至少在您确实希望这样做的情况下也是如此。广泛的用户友好性/兼容性,因为缺少尾随换行符会在各种情况下增加其他困难(连接/打印多个文本文件,使用典型的命令行工具进行解析,诸如busybox的最小编辑器vi等)。
mtraceur '16

(1)在VMS之前,RT-11 RSX-11 TOPS-10的文件系统仅精确到一个块,并且需要EOF字符。CP / M也是如此,它显然是从DEC复制的,然后又被早期的MS-DOS复制,然后传递到Windows。(2)在Unix中,它是tty驱动程序而不是外壳程序,如JohanM所详细描述的,尽管人们通常在tty设备上运行外壳程序。
dave_thompson_085

当然-DEC回到了那里(请注意,我提到的是版本)。CP / M功能的起源是否是一个有趣的话题(不在此处);我提到这些案例是为替代方法提供一些背景知识。
Thomas Dickey

7

EOF不是字符。它是一种状态,指示不再需要从文件流中读取字符。从终端输入EOF命令时,您正在向OS发送信号以关闭输入流,而不用输入特殊字符。


1
是的,但是在ASCII表中EOF是26,所以我认为最后一个字节是26的二进制表示形式。那么读取输入的程序怎么知道它的结尾呢?
sworwitz

ASCII旨在通过网络传递信息。在这种情况下,您需要一个EOF字符。(ASCII也有很多控制代码。并非所有内容都可以打印。)对于文件流,文件的大小已经通过文件系统得知,因此OS可以告诉您何时没有更多数据可读取。
Munir

@sworwitz:关于C,每次读取返回一个字符的输入读取函数返回一个int(通常是32位数字,但必须至少为16位)而不是char。该函数通过返回-1(0xffffffff)(不是有效的8位值)来表示信号和EOF,因此不会与任何ASCII字符(甚至0xff)混淆。返回字符串的函数还返回读取数据的长度。此长度可用于表示无数据或数据末尾(同样,长度可以为-1)。最后,还有一个您可以调用的函数,它将告诉您流是否已到达末尾
slebetman's

好的谢谢!因此,在bash中按Ctrl + d时,我输入了ASCII字符,对吗?
sworwitz '16

@sworwitz不完全是。在bash获得输入之前,由TTY驱动程序对其进行按摩。该驱动程序拦截Ctrl-D并将EOF发送给bash (其中EOF不是字符,而是特殊文件状态)
Stig Hemmer
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.