你是否也和我一樣曾經好奇過為什么回車叫做回車呢?回車回的是哪門子的車,哪來的車?你是否知道回車和換行的區別呢?
前傳
在展開這個話題之前先說一個身邊的故事。下面一段代碼是同事寫來處理一個簡單的文件然后輸出到另一個文件的代碼,大家覺得有什么問題么?
string content; using (StreamReader sr = new StreamReader("a.txt")) { content = sr.ReadToEnd(); } string[] rows = content.Split('\n'); string result = string.Empty; using (StreamWriter sw = new StreamWriter("b.txt")) { foreach (var row in rows) { //處理row sw.WriteLine(row); } }
最后發現b.txt在某一些編輯器中每一行中間都多了一個空行,但是代碼里明明是每一行寫一次的,怎么會出現空行呢?
問題就處在content.Split('\n');
這句話,因為在Windows下文件的行末包含兩個字符\r\n
,而不是僅僅是\n
。用Notepad++打開一個文件看一下一目了然了:
回車和換行前世今生
回到最開始的那個問題,換行符尚可理解,但是回車符這名字好奇怪,而且換一個行為毛需要兩個特殊字符呢?
記得前幾天看過一篇關於光速安振創投副總裁張矩(Google前員工)的采訪:
Google認為計算機科學完全是由人基於理性的設計,和物理、化學等基礎性學科不一樣,它背后的原理是人可以理解的,也唯有理解了原理之后,才能學會創新。例如你需要了解TCP/IP為什么會設計成這樣,而不是只知道它是什么。在Google看來,只要人的基礎足夠好,在他們的環境下就可以做好,而且環境變了,以前的經驗未必有用。Google最早的幾個員工里,也只有兩個來自計算機專業。
計算機里的一些設計往往是由特定的原因或者歷史問題才存在的,那么這個奇怪的回車是為什么存在呢?
從打字機說起
人們在使用最開始的打字機的時候,當打到一行末尾需要換行的時候,需要做兩個操作。第一個就是拉動carriage講紙回到行首,然后再拉動換行桿將紙張向下移動一行。這個設計影響了之后電傳打印機的設計,而電傳打印機的設計間接的影響了最開始計算機系統中的一部分設計(因為最開始的計算機需要兼容電傳打印機)。
打印機的那個裝置叫做Carriage,於是回到行首的這個操作就叫做Carriage Return,翻譯成中文就變成了回車,這里的車其實是打印機上的一個裝置。后來的打字機則將這兩個操作合並到了一個操作裝置上去了。
ASCII碼的設計
大家都知道\r
和\n
是包含在ASCII碼中的,ASCII是由ISO和ASA(ASNI的前身)同時設計的,在ISO的標准草稿中支持CR
+LF
或LF
作為新行標識,而ASA的標准草稿則支持CR
+LF
。
CR
+LF
之所以同時使用是為了兼容當時的電傳打印機,和老式打印機一樣電傳打印機需要兩個指令來完成一次換行。所以后來的很多系統中都沿用了這個CR
+LF
的慣例,將它們作為新行的標識。
混亂的現狀
雖然很多系統沿用了這個慣例,但是還是有很多其他的系統使用了不同的換行方式。
Windows:CR
+ LF
Unix及類Unix系統(Linux, OS X):LF
老板本
MacOS:CR
大部分的文本相關的因特網協議(Http, FTP, IRC, SMTP)都強制使用ASCII碼 CR
+LF
做換行符。
這就導致了一個問題,文件如果從一個系統直接拷貝到另一個系統就需要對其中的換行符進行轉換才能夠正確的使用。
P.S.: 純屬YY, 我覺得把Carriage Return翻譯成回頭也許更加合理一些! 😄