为什么文本文件应该以换行符结尾?

Why should text files end with a newline?

提问人:Will Robertson 提问时间:4/8/2009 最后编辑:mirekphdWill Robertson 更新时间:9/27/2023 访问量:386584

问:

我想这里的每个人都熟悉一句格言,即所有文本文件都应以换行符结尾。我早就知道这个“规则”,但我一直想知道——为什么?

文件 UNIX 文本文件 POSIX 换行符

评论

47赞 gcb 7/11/2013
只是吹毛求疵。它不是文件末尾的“换行符”。这是最后一行末尾的“换行符”。另外,请参阅相关问题的最佳答案:stackoverflow.com/questions/16222530/...
493赞 sindrenm 6/6/2014
只是为了吹毛求疵,他实际上并没有写“换行”,他写了“换行”,这是正确的。
6赞 tobibeer 2/14/2015
不熟悉,但想知道我确实是,因为那个多余的换行符实际上破坏事情的情况数量对我的口味来说有点太高了
5赞 Mark K Cowan 9/12/2015
我目前正在使用 Node.js 流逐行解析纯文本数据,缺少终端换行符很烦人,因为我必须为流的输入端完成/关闭时添加额外的逻辑,以确保最后一行得到处理。
51赞 MarkDBlackwell 8/29/2016
Unix 在文件末尾处理其一般行为的方式如下:\n 字符不开始行;相反,他们结束了他们。因此,\n 是行终止符,而不是行分隔符。第一行(与所有行一样)不需要 \n 即可启动它。最后一行(与所有行一样)需要 \n 来结束它。文件末尾的 \n 不会创建其他行。但是,有时文本编辑器会在此处添加一个可见的空行。甚至 emacs 也可以选择这样做。

答:

13赞 Marc Gravell 4/8/2009 #1

大概只是一些解析代码期望它在那里。

我不确定我是否会将其视为“规则”,这当然不是我虔诚地遵守的。大多数明智的代码将知道如何逐行(任何行尾选择)解析文本(包括编码),在最后一行上有或没有换行符。

事实上 - 如果你以新行结尾:(理论上)EOL 和 EOF 之间是否有空的最后一行?值得深思...

评论

13赞 MestreLion 8/28/2013
这不是一个规则,而是一个惯例:行是以行尾结尾的东西。所以不,EOL 和 EOF 之间没有“空的最后一行”。
4赞 Ben Voigt 6/21/2015
@MestreLion:但是有问题的字符不是被命名为“行尾”,而是被命名为“换行符”和/或“换行符”。行分隔符,而不是行终止符。结果是最后的空行。
3赞 MestreLion 6/30/2015
没有(理智的)工具会将文件的最后一个 EOL(CR、LF 等)计为额外的空行。如果没有结束的 EOL,所有 POSIX 工具都不会将文件的最后一个字符计为一行。无论 EOL 字符名称是“换行符”还是“回车符”(没有名为“换行符”的字符),对于所有实用的实用工具来说,明智的工具都将其视为行终止符,而不是行分隔符
3赞 Pacerier 7/3/2015
@MestreLion,你确定“线路终结者”是理智的吗?找几个非程序员,做一个快速的调查。您很快就会意识到线的概念更接近于“线分隔符”的概念。“行终结者”的概念很奇怪
5赞 MestreLion 10/13/2015
@Sahuagin:这不是的观点,这是POSIX标准对一行的定义。一个字节为 0 的空文件有 0 行,因此没有 EOL,而一个文件被认为只有一个空行,它确实需要 EOL。另请注意,这仅在您想计算文件上的行数时才有意义,因为显然任何编辑器都会让你“获取”下一行(或第一行),无论那里是否已经有 EOL。
24赞 cgp 4/8/2009 #2

基本上,如果许多程序没有获得最终的EOL EOF,它们将无法正确处理文件。

GCC 会就此发出警告,因为它是 C 标准的一部分。(显然是第 5.1.1.2 节)

编译器警告“文件末尾没有换行符

评论

5赞 Bill the Lizard 4/8/2009
GCC 并非无法处理文件,它必须作为 C 标准的一部分发出警告。
0赞 Mark K Cowan 9/16/2016
IIRC,MSVC 2005 抱怨 C 文件以不完整的行结尾,并且可能拒绝编译它们。
-6赞 User 4/8/2009 #3

我个人喜欢源代码文件末尾的新行。

就此而言,它可能起源于 Linux 或所有 UNIX 系统。我记得有编译错误(如果我没记错的话,gcc),因为源代码文件没有以空换行符结尾。为什么会这样,人们不禁要问。

310赞 Bill the Lizard 4/8/2009 #4

每一行都应以换行符结尾,包括最后一行。如果文件的最后一行未以换行符结尾,则某些程序在处理文件的最后一行时会出现问题。

GCC 警告它不是因为它无法处理文件,而是因为它必须作为标准的一部分。

C语言标准说 不为空的源文件应以换行符结尾,换行符前不应紧跟反斜杠字符。

由于这是一个“shall”子句,因此我们必须发出违反此规则的诊断消息。

这是在 ANSI C 2.1.1.2 标准的第 1989 节中。ISO C 1999 标准(可能还有 ISO C 1990 标准)的第 5.1.1.2 节。

参考资料:GCC/GNU 邮件存档

评论

24赞 tobibeer 2/14/2015
请编写好的程序,然后允许在处理时在需要的地方插入该换行符,或者能够正确处理“丢失”的换行符......事实上,这些并没有丢失
4赞 Pacerier 7/3/2015
@BilltheLizard,“如果文件的最后一行没有换行符终止,某些程序在处理文件的最后一行时会遇到问题”,有哪些示例?
10赞 Bill the Lizard 7/3/2015
如果文件没有换行符终止,则@Pacerier不会计算文件的最后一行。此外,如果第一个文件的最后一行未以换行符结尾,则将文件的最后一行与下一个文件的第一行合并为一行。几乎任何寻找换行符作为分隔符的程序都有可能搞砸这一点。wc -lcat
2赞 Pacerier 7/3/2015
@BilltheLizard,我的意思是已经提到过了......wc
3赞 Pacerier 7/4/2015
@BilltheLizard,我的错,澄清一下:如果文件的最后一行没有换行符终止,有哪些程序在处理文件的最后一行时出现问题的例子(除了那些已经在线程上大量提及的程序,如和)?catwc
65赞 VonC 4/8/2009 #5

这可能与以下两者的区别有关:

  • 文本文件(每行都应以行尾结尾)
  • 二进制文件(没有真正的“行”可言,必须保留文件的长度)

例如,如果每一行都以行尾结尾,则可以避免连接两个文本文件会使第一个运行的最后一行进入第二个运行的第一行。

此外,编辑器可以在加载时检查文件是否以行尾结尾,将其保存在其本地选项“eol”中,并在写入文件时使用它。

几年前(2005 年),许多编辑(ZDE、Eclipse、Scite 等)确实“忘记”了最终的 EOL,这并不十分受欢迎
不仅如此,他们还错误地将最终的 EOL 解释为“开始一条新行”,实际上开始显示另一条线,就好像它已经存在一样。
与在上述编辑器之一中打开它相比,使用像 vim 这样表现良好的文本编辑器的“正确”文本文件非常明显。它在文件的实际最后一行下方显示一行额外的行。你会看到这样的东西:

1 first line
2 middle line
3 last line
4

评论

13赞 MestreLion 8/28/2013
+1.我在遇到这个问题时发现了这个 SO 问题。Eclipse 显示这个“假”的最后一行非常烦人,如果我删除它,那么 git(以及所有其他期望 EOL 的 unix 工具)就会抱怨。另外,请注意,这不仅发生在 2005 年:Eclipse 4.2 Juno 仍然存在此问题。
0赞 Pacerier 7/3/2015
@MestreLion,stackoverflow.com/questions/729692/ 的延续......
2赞 Pippen_001 4/8/2009 #6

想象一下,文件正在处理中,而文件仍在由另一个进程生成。

这可能与此有关?指示文件已准备好进行处理的标志。

-8赞 Torben Gundtofte-Bruun 4/8/2009 #7

恕我直言,这是个人风格和意见的问题。

在过去,我没有输入换行符。保存的字符意味着通过 14.4K 调制解调器的速度更快。

稍后,我放置了该换行符,以便使用 shift+downarrow 更轻松地选择最后一行。

19赞 Stefan 4/8/2009 #8

这起源于使用简单终端的早期。换行符用于触发传输数据的“刷新”。

今天,不再需要换行符字符。当然,如果没有换行符,许多应用程序仍然有问题,但我认为这些应用程序中的错误。

但是,如果您的文本文件格式需要换行符,则可以非常便宜地获得简单的数据验证:如果文件以末尾没有换行符的行结尾,则知道文件已损坏。每行只有一个额外的字节,您可以高精度地检测损坏的文件,并且几乎没有 CPU 时间。

评论

18赞 MestreLion 8/28/2013
如今,文本文件的 EOF 换行符可能不是必需的,但它是一种有用的约定,使大多数 UNIX 工具协同工作并具有一致的结果。这根本不是错误。
18赞 DaveWalley 8/6/2014
我们中的许多人根本不使用 Unix 工具,我们也不关心。
14赞 Sam Watkins 12/4/2014
这不仅仅是 unix 工具,任何工具如果可以采用合理的文件格式,它就会更好地工作和/或编码更简单。
3赞 chux - Reinstate Monica 6/20/2015
@Sam Watkins:同意拥有简单、定义良好的格式是好的。然而,代码仍然需要验证,而不是假设数据符合格式。
11赞 polkovnikov.ph 12/5/2016
@MestreLion 这是一组符合愚蠢标准的不良工具的无用遗产。这些极端主义编程的产物(即一切都是文件!一切都应该说纯文本!)在发明后不久就没有消亡,因为它们是历史某个时刻唯一可用的工具。C被C++取代,它不是POSIX的一部分,它不需要EOF的EOL,并且*nix luddists(显然)不鼓励使用它。
1888赞 Konrad Rudolph 4/8/2009 #9

因为这就是POSIX标准定义的方式

3.206线
零个或多个非<换行符>加上终止<换行符>字符的序列。

因此,不以换行符结尾的“行”不被视为实际行。这就是为什么某些程序在处理文件的最后一行时出现问题,如果它没有换行符终止。

遵循此约定的优点是所有 POSIX 工具都期望并使用它。例如,当将文件与 连接起来时,以换行符(及以下)结尾的文件将具有与不带 () 的文件不同的效果:cata.txtc.txtb.txt

$ more a.txt
foo

$ more b.txt
bar
$ more c.txt
baz

$ cat {a,b,c}.txt
foo
barbaz

为了保持一致性,我们遵循此规则。否则,在处理默认的 POSIX 工具时会产生额外的工作。


换个角度想:如果行不是以换行符结尾的,那么使诸如 useful 之类的命令变得更加困难:您如何制作命令来连接文件,以便cat

  1. 它将每个文件的开头放在一个新行上,这是您 95% 的时间想要的;但
  2. 它允许合并两个文件的最后一行和第一行,如上面的示例中所示,在 和 ?b.txtc.txt

当然,这是可以解决的,但您需要使 的使用更加复杂(例如,通过添加位置命令行参数),现在命令而不是每个单独的文件控制它如何与其他文件粘贴在一起。这几乎肯定是不方便的。catcat a.txt --no-newline b.txt c.txt

...或者,您需要引入一个特殊的哨兵字符来标记应该继续而不是终止的行。好吧,现在您遇到了与 POSIX 相同的情况,除了倒置(行延续而不是行终止字符)。


现在,在不符合 POSIX 标准的系统(现在主要是 Windows)上,这一点是没有意义的:文件通常不以换行符结尾,例如,行的(非正式)定义可能是“用换行符分隔的文本”(注意强调)。这是完全有效的。然而,对于结构化数据(例如编程代码),它使解析变得更加简单:这通常意味着必须重写解析器。如果解析器最初是根据 POSIX 定义编写的,那么修改令牌流而不是解析器可能更容易——换句话说,在输入的末尾添加一个“人工换行符”标记。

评论

46赞 Doug Coburn 12/7/2018
虽然现在纠正起来很不切实际,但显然POSIX在定义这条线时犯了一个错误——关于这个问题的问题数量就是证明。一行应定义为以 <eol>、<eof> 或 <eol><eof> 结尾的零个或多个字符。解析器的复杂性不是一个有效的问题。只要有可能,复杂性就应该从程序员的头脑转移到库中。
85赞 Konrad Rudolph 12/7/2018
@DougCoburn 这个答案曾经有一个详尽的技术讨论,解释为什么这是错误的,以及为什么POSIX做了正确的事情。不幸的是,这些评论显然最近被一位过分热心的版主删除了。简而言之,这与解析复杂性无关;相反,您的定义使编写工具变得更加困难,例如以一种既有用又一致的方式。cat
44赞 Konrad Rudolph 2/12/2019
@Leon POSIX规则旨在减少边缘情况。它做得很漂亮。实际上,我有点不明白人们为什么无法理解这一点:这是一条线的最简单、自洽的定义。
21赞 Konrad Rudolph 2/12/2019
@BT 我认为您认为我关于更方便的工作流程的例子是决定背后的原因。不是,这只是一个结果。原因是 POSIX 规则是最简单的规则,这使得在解析器中处理行最容易。我们甚至进行辩论的唯一原因是 Windows 以不同的方式进行,因此,有许多工具在 POSIX 文件上失败。如果每个人都做POSIX,就不会有任何问题。然而,人们抱怨的是 POSIX,而不是 Windows。
21赞 Konrad Rudolph 2/14/2019
@BT 我指的是 Windows 只是为了指出 POSIX 规则没有意义的情况(换句话说,我扔了你一根骨头)。我很高兴在这次讨论中再也不提它了。但是,您的主张就更没有意义了:在 POSIX 平台上,讨论具有不同行尾约定的文本文件根本没有意义,因为没有理由生成它们。有什么优势?从字面上看没有。— 总而言之,我真的不明白这个答案(或 POSIX 规则)正在产生的仇恨。坦率地说,这是完全不合理的。
3赞 he_the_great 7/2/2009 #10

我一直认为这条规则来自解析没有结束换行符的文件很困难的日子。也就是说,您最终会编写由EOL字符或EOF定义的行尾代码。假设一行以 EOL 结尾更简单。

但是,我相信该规则源自需要换行符的 C 编译器。正如“文件末尾没有换行符”编译器警告所指出的,#include 不会添加换行符。

52赞 Flimm 10/12/2011 #11

一些工具期望这一点。例如,期望以下内容:wc

$ echo -n "Line not ending in a new line" | wc -l
0
$ echo "Line ending with a new line" | wc -l
1

评论

28赞 MestreLion 8/28/2013
我不会说“一些”,我说大多数工具都希望文本文件如此,如果不是全部的话。cat、git、diff、wc、grep、sed......名单很大
1赞 Guildenstern 5/10/2016
也许有人会说,这并不期望这一点,因为它只是在POSIX对“线”的定义中工作,而不是大多数人对“线”的直观理解。wc
0赞 Flimm 5/10/2016
@Guildenstern 直观的定义是在两种情况下都打印,但有些人可能会说第二种情况应该打印。wc -l12
1赞 semicolon 4/5/2017
@Flimm 如果你把它看作是一个行终止符,而不是像 POSIX/UNIX 那样作为一个行分隔符,那么期望第二个案例打印 2 绝对是疯狂的。\n
12赞 l0b0 11/4/2011 #12

还有一个实际的编程问题,文件末尾缺少换行符:内置的 Bash(我不知道其他实现)无法按预期工作:readread

printf $'foo\nbar' | while read line
do
    echo $line
done

打印只有 foo!原因是当遇到最后一行时,它会将内容写入但返回退出代码 1,因为它到达了 EOF。这打破了循环,因此我们永远无法到达零件。如果要处理这种情况,则必须执行以下操作:read$linewhileecho $line

while read line || [ -n "${line-}" ]
do
    echo $line
done < <(printf $'foo\nbar')

也就是说,由于文件末尾的非空行而失败,请执行 if。当然,在这种情况下,输出中将有一个额外的换行符,而该换行符不在输入中。echoread

130赞 Milan Adamovsky 8/15/2014 #13

这个答案是对技术答案的尝试,而不是意见。

如果我们想成为POSIX纯粹主义者,我们将一条线定义为:

零个或多个非<换行符>加上终止<换行符>字符的序列。

来源:https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206

不完整的行如下:

文件末尾的一个或多个非<换行符>字符的序列。

来源:https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_195

文本文件为:

包含组织成零行或多行的字符的文件。这些行不包含 NUL 字符,并且长度不得超过 {LINE_MAX} 字节,包括 <newline> 字符。尽管 POSIX.1-2008 不区分文本文件和二进制文件(参见 ISO C 标准),但许多实用程序仅在对文本文件进行操作时才产生可预测或有意义的输出。具有此类限制的标准实用程序始终在其 STDIN 或 INPUT FILES 部分中指定“文本文件”。

来源: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_397

字符串如下:

由第一个 null 字节终止并包括第一个 null 字节的连续字节序列。

来源:https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_396

由此,我们可以得出,我们唯一可能遇到任何类型的问题的情况是,如果我们将文件的一行或文件作为文本文件的概念进行处理(因为文本文件是零行或多行的组织,并且我们知道的一行必须以<换行符>结尾)。

举个例子:.wc -l filename

从手册中我们读到:wc

行定义为由<换行符>字符分隔的字符串。

那么,JavaScript、HTML 和 CSS 文件是文本文件有什么含义?

在浏览器、现代 IDE 和其他前端应用程序中,在 EOF 跳过 EOL 没有问题。应用程序将正确解析文件。它必须如此,因为并非所有操作系统都符合 POSIX 标准,因此非操作系统工具(例如浏览器)根据 POSIX 标准(或任何操作系统级标准)处理文件是不切实际的。

因此,我们可以相对确信,EOF的EOL在应用程序级别几乎不会产生负面影响 - 无论它是否在UNIX操作系统上运行。

在这一点上,我们可以自信地说,在客户端处理 JS、HTML、CSS 时,在 EOF 跳过 EOL 是安全的。实际上,我们可以说缩小这些文件中的任何一个,不包含<换行符>都是安全的。

我们可以更进一步,说就 NodeJS 而言,它也不能遵守 POSIX 标准,因为它可以在不符合 POSIX 的环境中运行。

那我们还剩下什么呢?系统级工具。

这意味着可能出现的唯一问题是那些努力将其功能与 POSIX 语义保持一致的工具(例如,如 所示的行的定义)。wc

即便如此,并非所有 shell 都会自动粘附 POSIX。例如,Bash 不默认为 POSIX 行为。有一个开关可以启用它:。POSIXLY_CORRECT

关于EOL的价值的思考<换行符>:https://www.rfc-editor.org/old/EOLstory.txt

保持在工具轨道上,出于所有实际意图和目的,让我们考虑一下:

让我们使用一个没有 EOL 的文件。在撰写本文时,此示例中的文件是没有 EOL 的缩小 JavaScript。

curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o x.js
curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o y.js

$ cat x.js y.js > z.js

-rw-r--r--  1 milanadamovsky   7905 Aug 14 23:17 x.js
-rw-r--r--  1 milanadamovsky   7905 Aug 14 23:17 y.js
-rw-r--r--  1 milanadamovsky  15810 Aug 14 23:18 z.js

请注意,文件大小正好是其各个部分的总和。如果 JavaScript 文件的串联是 JS 文件的关注点,那么更合适的关注点是以分号开头每个 JavaScript 文件。cat

正如其他人在此线程中提到的:如果您想要两个输出仅为一行而不是两行的文件怎么办?换句话说,做它应该做的事情。catcat

of 只提到读取 EOF 的输入,而不是<换行>。请注意,开关 还将打印出非<换行符>终止行(或不完整行)作为 - 因为计数从 1 开始(根据 .)mancat-ncatman

-n 对输出行进行编号,从 1 开始。

现在我们了解了 POSIX 如何定义一条线,这种行为变得模棱两可,或者说实际上不合规。

了解给定工具的用途和合规性将有助于确定使用 EOL 结束文件的重要性。在 C、C++、Java (JAR) 等中...有些标准会规定一个换行符来表示有效性——JS、HTML、CSS 不存在这样的标准。

例如,与其使用 one can do ,不如放心,任务的成功不会受到我们可能想要处理的文件(例如第三方库,例如我们 d 的缩小 JS )的影响——除非我们的意图是真正计算符合 POSIX 的wc -l filenameawk '{x++}END{ print x}' filenamecurl

结论

在现实生活中,对于某些文本文件(如 JS、HTML 和 CSS)在 EOF 中跳过 EOL 会产生负面影响(如果有的话)。如果我们依赖于<换行符>的存在,我们将工具的可靠性限制在我们创作的文件上,并使自己容易受到第三方文件引入的潜在错误的影响。

故事的寓意:工程师工具没有在EOF上依赖EOL的弱点。

请随时发布适用于 JS、HTML 和 CSS 的用例,我们可以在其中研究跳过 EOL 如何产生不利影响。

评论

3赞 Luis Colorado 11/22/2017
问题中未标记 POSIX...对 MVS/OS 行尾的看法?还是 MS-DOS 行尾?顺便说一句,所有已知的 posix 系统都允许没有最后一行结尾的文本文件(没有发现符合 posix 的声明系统的情况,其中“文本文件”在内核中具有特殊处理以插入适当的换行符,以防它没有)
7赞 Dem Pilafian 11/4/2020
“在现实生活中,很少有跳过的用例......”。不对。在现实生活中,我每天都在审查代码,处理由于文件缺少尾随而导致的无用的合并差异是浪费时间。为了保持一致性,每一行(甚至是文件中的最后一行)都应正确终止。newline
0赞 Beni Cherniavsky-Paskin 5/23/2022
POSIX对“文本行”的定义是相关的,因为他们可以在标准中引用,例如 不会计算最后一行不完整。但它是否渴望规范语义,并不重要;UNIX I/O 的一个非常重要的特性是它不是面向记录的,它只是一个由 8 位八位字节组成的平面序列——任何含义都是由单个程序分配的!大多数核心公用事业公司都尊重这一点,并尽量不扼杀任何输入。例如,它是面向线的,但它必须发明符号,因为这是唯一的区别。wc -ldiff\ No newline at end of file
9赞 chux - Reinstate Monica 6/20/2015 #14

为什么(文本)文件应该以换行符结尾?

正如许多人所表达的那样,因为:

  1. 许多程序表现不佳,或者没有它就无法失败。

  2. 即使是很好地处理文件的程序也缺乏结尾,该工具的功能可能无法满足用户的期望 - 在这种极端情况下可能不清楚。'\n'

  3. 程序很少禁止最终(我不知道有)。'\n'


然而,这引出了下一个问题:

代码应该如何处理没有换行符的文本文件?

  1. 最重要的是 - 不要编写假定文本文件以换行符结尾的代码假设文件符合某种格式会导致数据损坏、黑客攻击和崩溃。例:

    // Bad code
    while (fgets(buf, sizeof buf, instream)) {
      // What happens if there is no \n, buf[] is truncated leading to who knows what
      buf[strlen(buf) - 1] = '\0';  // attempt to rid trailing \n
      ...
    }
    
  2. 如果需要最后的尾随,请提醒用户它的缺失和所采取的操作。IOW,验证文件的格式。注意:这可能包括对最大行长、字符编码等的限制。'\n'

  3. 明确定义,文档,代码对缺失的最终的处理。'\n'

  4. 尽可能不要生成缺少结尾的文件。'\n'

19赞 jrw32982 9/25/2015 #15

除了上述实际原因之外,如果 Unix 的创始人(Thompson、Ritchie 等人)或他们的 Multics 前辈意识到使用行终止符而不是行分隔符是有理论原因的,我不会感到惊讶:使用行终止符,您可以对所有可能的行文件进行编码。使用行分隔符,零行文件和包含单个空行的文件之间没有区别;它们都被编码为包含零个字符的文件。

所以,原因是:

  1. 因为这就是POSIX定义它的方式。
  2. 因为有些工具期望它或没有它“行为不端”。例如,如果最后一个“行”不以换行符结尾,则不会计算该行。wc -l
  3. 因为它简单方便。在 Unix 上,它只是工作,而且它工作起来没有复杂性。它只是复制每个文件的字节,不需要任何解释。我不认为有 DOS 等效于 .使用 将最终将文件的最后一行与文件的第一行合并。catcatcopy a+b cab
  4. 因为零行的文件(或流)可以与一空行的文件区分开来。
24赞 symbiont 3/6/2016 #16

多年来,我自己也一直在思考这个问题。但我今天遇到了一个很好的理由。

想象一个每行都有一条记录的文件(例如:CSV 文件)。并且计算机正在文件末尾写入记录。但它突然崩溃了。哎呀,最后一行完成了吗?(不是一个好情况)

但是,如果我们总是终止最后一行,那么我们就会知道(只需检查最后一行是否终止)。否则,为了安全起见,我们可能每次都不得不丢弃最后一行。

评论

0赞 alfC 4/30/2021
我同意,我一直认为这是一个穷人的“校验和”,它说当行尾缺失时,它表明文件可能被截断了。当然,这并不能保证相反。至少对于文本文件;对于二进制文件,我不知道它是否是有效的约定。
0赞 symbiont 4/30/2021
@alfC这是一个很好的描述。这就是我使用它的方式。是的,这当然不适用于二进制文件
2赞 B T 8/25/2022
这实际上是一个可怕的原因。您的文件系统应该用于处理此问题。现代文件系统是日志式的,这是识别文件写入是否完成的一种更好的方法,因为它适用于二进制文件和文本文件,并且具有上次写入的实际历史记录。
1赞 symbiont 8/29/2022
@BT这取决于您所说的“文件写入”是什么意思。当我遇到这种情况(反复)时,最后一行没有完全写入,它位于日志文件系统上
0赞 Walf 12/21/2023
@BT并非所有文件都直接写入本地文件系统。流、对象存储等确实存在。那些抱怨不得不在最后一行使用换行符的人——通常是出于相当肤浅的原因——会很乐意在数组条目上使用尾随逗号,或者在支持它们的编程语言上使用函数参数。
44赞 Robin Whittleton 9/5/2016 #17

一个单独的用例:提交卫生,当您的文本文件受到版本控制时。

如果将内容添加到文件末尾,则之前作为最后一行的行将被编辑为包含换行符。这意味着,在文件中找出该行上次编辑的时间将显示换行符添加,而不是您真正想要查看的提交。blame

(该示例特定于 git,但相同的方法也适用于其他版本控制系统。

评论

3赞 Andrew 5/11/2019
diff 和 blame 应该只是更新以检测“新行”而不是“换行符”()。问题解决了。\n
3赞 Robin Whittleton 7/10/2019
您可以使用 -w 标记来忽略空格更改,但它们不是默认更改。
4赞 Dave Cousineau 8/23/2021
这是我开始在文件末尾放置换行符的主要原因
0赞 Walf 12/18/2023
@Andrew 问题根本没有解决。有人可能希望在有或没有终止换行符的情况下提交文件的原因有很多。改变任何 Git 工具,对开发人员的“真正意思”做出幼稚的假设,而不是按原样提交和差异文件,这是一个非常愚蠢的想法。
0赞 Andrew 12/20/2023
@Walf我不确定我当时是否包含提交,或者只是考虑提到的文字工具(尽管我知道它基本上与提交不同)。我确实认为至少同时拥有字面和非字面选项是有价值的。现在,我更倾向于让IDE清理它,例如,就像他们经常对尾随空格所做的那样。我确实发现文件末尾的额外行,为了管道或其他原因,是令人讨厌和不必要的。
6赞 Arpit 11/23/2018 #18

现在已经很晚了,但我只是在文件处理中遇到了一个错误,这是因为文件没有以空换行符结尾。我们正在处理文本文件,并省略了输出中的最后一行,这会导致无效的 json 结构并将进程的其余部分发送到失败状态。sedsed

我们所做的只是:

有一个示例文件说:里面有一些内容。foo.txtjson

[{
    someProp: value
},
{
    someProp: value
}] <-- No newline here

该文件是在 widows 计算机中创建的,窗口脚本使用 PowerShell 命令处理该文件。都很好。

当我们使用命令处理相同的文件时sedsed 's|value|newValue|g' foo.txt > foo.txt.tmp

新生成的文件是

[{
    someProp: value
},
{
    someProp: value

和 boom,由于无效的 JSON,它使其余进程失败。

因此,最好以空换行符结束文件。

评论

0赞 darw 10/5/2020
echo -n foo | sed '{}'适用于sed (GNU sed) 4.4
0赞 Enlico 5/1/2021
用空换行符结束文件?什么是空换行
23赞 Enlico 5/1/2021 #19

为什么文本文件应该以换行符结尾?

因为这是最明智的选择。

获取包含以下内容的文件,

one\n
two\n
three

其中表示换行符,在 Windows 上是 ,返回字符后跟换行符,因为它太酷了,对吧?\n\r\n

这个文件有多少行?Windows 说 3,我们说 3,POSIX (Linux) 说文件是残缺的,因为它的末尾应该有一个。\n

无论如何,你会说它的最后一行是什么?我想任何人都同意这是文件的最后一行,但 POSIX 说这是一行残缺的行。three

它的第二行是什么?哦,这里我们有第一个强分离

  • Windows 说,因为文件是“用换行符分隔的行”(wth?two
  • POSIX说,并补充说这是一条真实、诚实的路线。two\n

那么,选择 Windows 的后果是什么呢?简单:

你不能说一个文件是由行组成的

为什么?尝试从上一个文件中获取最后一行并复制几次......你会得到什么?这:

one\n
two\n
threethreethreethree

相反,尝试交换第二行和第三行......你会得到这个:

one\n
threetwo\n

因此

您必须说文本文件是行和 \ns 的交替,它以一行开头,以一行结束

这很拗口,对吧?

你想要另一个奇怪的结果吗?

你必须接受一个空文件(0字节,实际上是0位)是一个单行文件,神奇的是,总是因为它们在Microsoft很酷

这很疯狂,你不觉得吗?

POSIX选择的后果是什么?

顶部的文件有点残缺,我们需要一些技巧来处理它。

认真

在前面的文本中,我是挑衅性的,因为处理缺少末尾的文本文件会迫使您使用临时的勾号/黑客来处理它们。你总是需要一个 / 某个地方来使事情正常工作,其中处理残缺线的分支只处理残缺的行,所有其他行都采用另一个分支。这有点种族主义,不是吗?\nifelse

我的结论

出于以下原因,我赞成POSIX对行的定义:

  • 文件自然而然地被设想为一系列行
  • 一行不应该是一回事或另一回事,这取决于它在文件中的位置
  • 空文件不是单行文件,来吧!
  • 你不应该被迫在你的代码中进行黑客攻击

是的,Windows 确实鼓励您省略尾随 .如果你想要一个两行文件,你必须省略尾随,否则文本编辑器会将其显示为三行文件:\r\n\r\nenter image description here

评论

1赞 Dave Cousineau 8/21/2021
你的回答让我不同意 POSIX 的选择。它不必要地引入了无效的文件状态,并使“换行符”的含义不正确。“换行符”应该被称为“行标记”,它是唯一将文本内容转换为行的东西,没有它,内容(出于某种原因)毫无意义。
0赞 Enlico 8/21/2021
@DaveCousineau,对不起,我不明白。为什么线标记是更好的选择?这是一个准确的名称吗?例如,它的名称中暗示它应该是行的尾随字符吗?行终结器可能是更好的选择。但无论如何,试着用 \n 替换换行符,你会看到你的注释是如何变化的:它使 \n 的含义不正确。\n 应改称为“线标记”。我会随心所欲地回答,即使是线毒贩,它仍然是一回事。
1赞 Enlico 8/21/2021
换行符、换行符、换行符、nuova riga、capo 或任何你想称呼它的东西,不是它的名字,而是它在 POSIX 定义行或文本文件中的作用。
1赞 Dave Cousineau 8/21/2021
“换行符”的含义是它制作了一个新行,但显然它没有。 相反,它使当前的非行变成一行。“行终结器”确实有效。但我仍然不认为我同意拥有不必要的无效状态。没有理由为什么“文本\n文本”不应该是可破译的文本。
0赞 Dave Cousineau 8/21/2021
我不确定这是否重要,但是如果我们说“行”必须至少有一个字符(即空字符串不是行),我们不必将 0 字节文件称为 1 行文件。也许我错过了什么。(我评论的上下文是,尽管我对此事有直觉,但我最近强迫自己开始在我的文本文件末尾添加一个“行终止符”。我仍然犹豫不决,但阅读您的答案使我不想添加它们。