回车符CR和换行符LF


我在Windows电脑上做开发时,经常会见到这个现象。代码从远程git仓库clone下来后,然后npm install安装依赖后,打开任意一个代码文件会看到每行结尾处有如下报红:

将鼠标指针停留在行尾报红处,会浮出如下提示:

Expected linebreaks to be 'LF' but found 'CRLF'.eslint(linebreak-style)

字面意思很清楚:期望换行是'LF',但发现是'CRLF'。(eslint换行风格)

LF和CRLF是什么东西呢?为什么会报红?为什么在MacOS上不会报红?这个代码规范问题又该如何解决呢?好了下面就是我追究的结论。


回车符和换行符是两个不同的字符。

回车符(CR:carriage return),字符编码为:十六进制0D,十进制13,转义字符为'\r';
换行符(LF:line feed),字符编码为:十六进制0A,十进制10,转义字符为'\n'

在Windows系统中的文本文件按Enter键换行,人眼看到编辑中只是换行了,但在文件二进制存储中实际上是两个字符(CRLF)。在类Unix系统(Unix、Linux、MacOS)中,文本文件按Enter键换行,这个换行在文件二进制存储中是一个字符(LF)。简言之,在Windows系统中换行默认是回车换行(CRLF)两个字符,在类Unix系统中换行默认是换行符(LF)一个字符。

【注:Mac OS 9 以及之前的系统的换行符是 CR,从 Mac OS X (后来改名为“OS X”)开始的换行符是 LF即‘\n',和Unix/Linux统一了。】

我们来验证一下,在Windows系统中创建一个纯文本文件,并用记事本NotePad打开并输入如下内容,用Enter键来换行:

我们看到文件大小是8字节,一共六个可见的字符(123abc),每个占一个字节,还有两个字符从何而来呢?

我们用UltraEdit编辑器,打开这个文件,并用十六进制模式查看文件二进制数据:

如上图所见,123和abc之间有个两个字符,十六进制编码分别为:0D、0A,0D是回车符,0A是换行符。

上面文件的字符编码格式是GBK的,我们用VS Code建一个utf-8的文件再试试:

可以看到文件换行默认采用CRLF,然后再用UltraEdit查看这个html文件的二进制数据:


可以看到所有换行处也都是CRLF两个字符,也就是说回车换行两个字符的二进制编码在不同编码方式下是相同的,都是0D和0A。

我们把上面CRLF in Windows.txt文件用VSCode打开,并将换行方式由CRLF改为LF:

然后保存文件:

再用UltraEdit打开文件,并查看二进制数据:


可以看到换行处只有一个字符0A,即换行符。

再看文件大小:


大小从之前的8字节变为7字节,也证明确实少了一个字节,少了的便是0D回车符。

这时我们再次用记事本NotePad打开这个文件:

可以看到abc没有换行,这再次证明,在Windows系统中要达到换行的效果,是需要回车和换行两个字符的。只有一个LF换行符,在最简单没有任何格式的编辑器(例如记事本)中是不会换行的,至于在一些比较专业化的程序代码编辑器中会换行,那只是编辑器的视觉优化,即见到0A这个字符(LF换行符)会显示成换行的效果。我们经常下载一些程序代码文件,用记事本打开发现没有换行,但用程序代码编辑器或强大的IDE中打开是正常换行的。这就是其中的原因。

然后再看下在Mac OS中如何,我们新建一个txt纯文本文件:

写入如下内容保存:

用UltraEdit打开此文件,并查看二进制数据:

可以看到换行处只有个字符0A换行符。

如果把换行规则改CRLF,文件的大小变成8字节:

在终端中运行:

vi -b CRLFinMacOS.txt

可以看到行尾有个 ^M,然后shit + :后再运行:

%!xxd

看到二进制数据中又出现了0D和0A,再次验证上面所说结论。

改天试一下在Linux上如何。


一片冰心在玉壶