歷史溯源:電傳打字機 (Teletype Model 33)
- CR (Carriage Return, \r, 0x0D):打印頭歸位行首。
- LF (Line Feed, \n, 0x0A):滾筒換行(紙張上移)。
- 機械限制:換行耗時 0.2s,需發送兩個結束字符防止數據丟失 → CRLF 雙字符結束行。
三大作業系統換行約定
| 系統 | 換行符 | 十六進制 | 備註 |
| Windows | \r\n | 0x0D 0x0A | 兼容早期打印機/終端 |
| Unix/Linux/macOS (現代) | \n | 0x0A | 只用 LF,節省存儲 |
| Classic Mac OS (9 及之前) | \r | 0x0D | 已淘汰 |
跨平台文件交換常見亂象
- Unix 文件在 Windows 記事本打開 → 全文變一行(無 CR,不識別換行)。
- Windows 文件在 Unix/Linux 下 → 行尾顯示 ^M (CR 字符)。
- Git 提交時
core.autocrlf 配置不當導致換行符反覆變更。
Java 中的轉義字符表
| 轉義序列 | 含義 | Unicode | 常用場景 |
\n | 換行 (LF) | U+000A | 日誌換行、文本生成 |
\r | 回車 (CR) | U+000D | 進度條覆蓋輸出、舊 Mac 兼容 |
\t | 水平製表 (Tab) | U+0009 | 對齊輸出、CSV 分隔 |
\b | 退格 | U+0008 | 控制台動畫 |
\f | 換頁 | U+000C | 打印控制 |
\\ | 反斜杠 | U+005C | 路徑、正則轉義 |
\' \" | 單/雙引號 | - | 字符串字面量內部 |
\uXXXX | Unicode 碼點 | - | 特殊字符、Emoji |
\r 覆蓋效果演示 (控制台)
System.out.print("Loading...\rDone! "); // 輸出: Done! (前綴被覆蓋)
System.out.println("Line1\rLine2"); // 輸出: Line2 (Line1 被覆蓋)
Java 獲取當前平台換行符(跨平台寫文件必用)
String lineSep = System.getProperty("line.separator"); // 推薦
// 或 Java 8+
String lineSep = System.lineSeparator();
// 寫文件示例
try (PrintWriter pw = new PrintWriter(new FileWriter("log.txt", true))) {
pw.print("ERROR: something wrong");
pw.print(lineSep); // 自動適配 Windows \r\n / Linux \n
}
控制台輸出特殊行為
Java 控制台 (System.out) 對 \n 和 \r 均視為換行(由終端模擬器處理),但文件/網絡傳輸必須嚴格區分。
最佳實踐清單
- 寫文本文件:統一使用
System.lineSeparator(),或 BufferedWriter.newLine()。
- 網絡協議 (HTTP/SMTP/Redis RESP):強制 \r\n (CRLF),按 RFC 標準。
- 日誌框架:Logback/Log4j2 內部已處理,直接用
%n 佔位符。
- Git 配置:
git config --global core.autocrlf input (提交轉 LF,檢出不轉),Linux/Mac 推薦;Windows 用 true。
- IDE 設置:File → Settings → Editor → Code Style → Line separator →
LF (統一倉庫風格)。