如何在 Java 中刪除檔案中的換行符
1. 概述
有時,我們需要從文件中讀取原始文本,並透過刪除換行符來清理雜亂的內容。
在本教程中,我們將探索從 Java 中的檔案中刪除換行符的各種方法。
2. 關於換行的一句話
在我們深入研究從檔案讀取和刪除換行符的程式碼之前,讓我們快速了解我們要刪除的目標物件:換行符。
乍一看,這非常簡單。換行符是一個字元換行。但是,有不同類型的換行符。如果我們不正確對待它們,我們可能會陷入陷阱。一個例子可以快速解釋它。
假設我們有兩個文字文件, mutiple-line-1.txt
和multiple-line-2.txt.
我們稱它們為file1
和file2.
如果我們在 IDE 的編輯器(例如 IntelliJ)中開啟它們,則兩個檔案看起來是一樣的:
A,
B,
C,
D,
E,
F
我們可以看到,每個檔案有六行,從第二行開始每行都有一個前導空格字元。因此,我們相信file1
和file2
包含確切的文字。
但是,現在讓我們使用帶有-n
(顯示行號)和-e
(顯示非列印字元)選項的cat
命令來列印檔案內容:
$ cat -ne multiple-line-1.txt
1 A,$
2 B,$
3 C,$
4 D,$
5 E,$
6 F$
file1's
輸出與我們在 IntelliJ 編輯器中看到的相同。但file2
看起來完全不同:
$ cat -ne multiple-line-2.txt
1 A,^MB,$
2 C,$
3 D,^ME,$
4 F$
這是因為有三種不同的換行符:
-
'\r'
– CR(回車),Mac OS 中 X 之前的換行符 -
'\n'
– LF(換行),*nix 和 Mac OS 中的換行符 -
'\r\n'
– CRLF,Windows 中的換行符
cat -e
將 CRLF 顯示為「 ^M
」。所以,我們看到file2
包含 CRLF。該文件可能是在 Windows 中建立的。根據需求,我們可能想要刪除所有類型的換行符或僅刪除目前系統的換行符。
接下來我們就以這兩個檔案為例,看看如何讀取其中的內容並移除換行符。為簡單起見,我們將建立兩個輔助方法來傳回每個檔案的Path:
Path file1Path() throws Exception {
return Paths.get(this.getClass().getClassLoader().getResource("multiple-line-1.txt").toURI());
}
Path file2Path() throws Exception {
return Paths.get(this.getClass().getClassLoader().getResource("multiple-line-2.txt").toURI());
}
3. 用空字串取代line.separator
系統屬性line.separator
儲存特定於目前作業系統的行分隔符號。因此,如果我們只想刪除目前系統特有的換行符,我們可以將line.separator
替換為空字串。例如,此方法刪除 Linux 機器上file1
中的所有換行符:
String content = Files.readString(file1Path(), StandardCharsets.UTF_8);
String result = content.replace(System.getProperty("line.separator"), "");
assertEquals("A, B, C, D, E, F", result);
我們使用Files
類別的readString()
方法來載入字串中的檔案內容。然後,我們透過replace()
應用替換。
但是,相同的方法不會刪除file2
中的所有換行符,因為它包含 CRLF 換行符:
String content = Files.readString(file2Path(), StandardCharsets.UTF_8);
String result = content.replace(System.getProperty("line.separator"), "");
assertNotEquals("A, B, C, D, E, F", result); // <-- NOT equals assertion!
接下來,讓我們看看是否可以獨立於系統中刪除所有換行符。
4. 用空字串取代“\n”和“\r”
我們已經了解了所有三種不同的換行符涵蓋“\n”和“\r”字元。因此,如果我們想獨立於系統刪除所有換行符,我們可以用空字串替換“ \n
”和“ \r
” :
String content1 = Files.readString(file1Path(), StandardCharsets.UTF_8);
// file contains CRLF
String content2 = Files.readString(file2Path(), StandardCharsets.UTF_8);
String result1 = content1.replace("\r", "").replace("\n", "");
String result2 = content2.replace("\r", "").replace("\n", "");
assertEquals("A, B, C, D, E, F", result1);
assertEquals("A, B, C, D, E, F", result2);
當然,我們也可以使用基於正規表示式的replaceAll()
方法來達到相同的目的。我們以file2為例,看看它是如何運作的:
String resultReplaceAll = content2.replaceAll("[\\n\\r]", "");
assertEquals("A, B, C, D, E, F", resultReplaceAll);
5. 使用readAllLines()
然後join()
讓我們回顧一下到目前為止我們學到的兩種方法。我們首先從檔案中讀取全部內容,然後將line.separator
系統屬性或「\n」和「\r」字元替換為空。這些方法之間的一個共同點是我們自己手動管理換行符。
Files
類別提供readAllLines()
將檔案內容讀入行並傳回字串清單。值得注意的是**readAllLines()
將所有提到的三個換行符號作為行分隔符號。換句話說,此方法從輸入中刪除所有換行符。我們需要做的是將返回列表中的元素連接起來**。
join()
方法可以非常方便地連接列表或字串陣列:
List<String> lines1 = Files.readAllLines(file1Path(), StandardCharsets.UTF_8);
// file contains CRLF
List<String> lines2 = Files.readAllLines(file2Path(), StandardCharsets.UTF_8);
String result1 = String.join("", lines1);
String result2 = String.join("", lines2);
assertEquals("A, B, C, D, E, F", result1);
assertEquals("A, B, C, D, E, F", result2);
六,結論
在本文中,我們首先討論了不同類型的換行符。然後,我們探索了從檔案中刪除換行符的各種方法。
與往常一樣,範例的完整原始程式碼可在 GitHub 上取得。