Java實(shí)現(xiàn)一行一行讀取文本的多種方法詳解
在Java中,有多種方式可以一行一行地讀取文本。以下是幾種常用的方法:
1. 使用 BufferedReader + FileReader
String str = "A\n" + "B\n" + "C";
// 方法1:從字符串讀取
try (BufferedReader reader = new BufferedReader(new StringReader(str))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
// 方法2:從文件讀取
try (BufferedReader reader = new BufferedReader(new FileReader("filename.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
2. 使用 Scanner
String str = "A\n" + "B\n" + "C";
// 從字符串讀取
try (Scanner scanner = new Scanner(str)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
}
}
// 從文件讀取
try (Scanner scanner = new Scanner(new File("filename.txt"))) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
3. 使用 Files.lines() (Java 8+)
String str = "A\n" + "B\n" + "C";
// 從字符串讀取(需要先寫入臨時(shí)文件)
try {
Path tempFile = Files.createTempFile("temp", ".txt");
Files.write(tempFile, str.getBytes());
Files.lines(tempFile).forEach(System.out::println);
// 清理臨時(shí)文件
Files.deleteIfExists(tempFile);
} catch (IOException e) {
e.printStackTrace();
}
// 從文件讀取
try {
Files.lines(Paths.get("filename.txt")).forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
4. 使用 String 的 split() 方法(適用于字符串)
String str = "A\n" + "B\n" + "C";
String[] lines = str.split("\n");
for (String line : lines) {
System.out.println(line);
}
//處理空行
String[] lines = str.split("\\r?\\n|\\r");
List<String> nonEmptyLines = Arrays.stream(lines)
.filter(line -> !line.trim().isEmpty())
.collect(Collectors.toList());
5. 使用 Lines() 方法 (Java 11+)
String str = "A\n" + "B\n" + "C"; // 從字符串讀取 str.lines().forEach(System.out::println);
推薦方案
- 對(duì)于字符串:使用
str.lines()(Java 11+) 或split("\n") - 對(duì)于文件:使用
Files.lines()(Java 8+) 或BufferedReader - 需要更多控制:使用
Scanner
最簡(jiǎn)潔的方式是使用 Java 11 的 lines() 方法:
String str = "A\n" + "B\n" + "C"; str.lines().forEach(System.out::println);
輸出結(jié)果:
A
B
C
在 Java 8 環(huán)境下,split("\n") 和 BufferedReader 各有優(yōu)缺點(diǎn),具體選擇取決于使用場(chǎng)景:
性能對(duì)比
1.split("\n")- 適用于小文本
String str = "A\n" + "B\n" + "C";
String[] lines = str.split("\n");
for (String line : lines) {
System.out.println(line);
}
優(yōu)點(diǎn):
- 代碼簡(jiǎn)潔,一行搞定
- 適合已知內(nèi)容較小的字符串
- 可以直接得到數(shù)組,方便后續(xù)處理
缺點(diǎn):
- 一次性加載所有內(nèi)容到內(nèi)存,大文本會(huì)占用大量?jī)?nèi)存
- 需要處理尾部的空行問題
2.BufferedReader- 適用于大文本或文件
String str = "A\n" + "B\n" + "C";
try (BufferedReader reader = new BufferedReader(new StringReader(str))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
優(yōu)點(diǎn):
- 內(nèi)存效率高,逐行讀取,適合大文件
- 自動(dòng)處理不同操作系統(tǒng)的換行符(
\n,\r\n,\r) - 統(tǒng)一的接口處理字符串和文件
缺點(diǎn):
- 代碼相對(duì)冗長(zhǎng)
- 需要處理異常
推薦選擇
場(chǎng)景 1:小文本,內(nèi)容已知且不大
// 使用 split("\n")
String[] lines = str.split("\n");
Arrays.stream(lines).forEach(System.out::println);
場(chǎng)景 2:大文本或需要處理文件
// 使用 BufferedReader
try (BufferedReader reader = new BufferedReader(new StringReader(str))) {
reader.lines().forEach(System.out::println); // Java 8 Stream API
} catch (IOException e) {
e.printStackTrace();
}
場(chǎng)景 3:Java 8 更優(yōu)雅的寫法
// 結(jié)合 BufferedReader 和 Stream API
try (BufferedReader reader = new BufferedReader(new StringReader(str))) {
List<String> lines = reader.lines().collect(Collectors.toList());
lines.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
實(shí)際建議
對(duì)于你的具體案例:
String str = "A\n" + "B\n" + "C";
// 如果確定文本很小,用 split 更簡(jiǎn)潔
String[] lines = str.split("\n");
for (String line : lines) {
System.out.println(line);
}
// 如果要養(yǎng)成好習(xí)慣或處理可能的大文本,用 BufferedReader
try (BufferedReader reader = new BufferedReader(new StringReader(str))) {
reader.lines().forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
總結(jié): 對(duì)于你當(dāng)前的小例子,split("\n") 完全足夠且更簡(jiǎn)潔。但如果考慮到代碼的可擴(kuò)展性和健壯性,BufferedReader 是更好的選擇。
Scanner 相比 BufferedReader 提供了更豐富的文本解析功能,主要在數(shù)據(jù)類型解析和分隔符控制方面有優(yōu)勢(shì)。
Scanner 的額外控制能力
1. 數(shù)據(jù)類型自動(dòng)解析
String data = "John 25 78.5 true\nAlice 30 65.2 false";
try (Scanner scanner = new Scanner(data)) {
while (scanner.hasNext()) {
if (scanner.hasNextInt()) {
int age = scanner.nextInt();
System.out.println("年齡: " + age);
} else if (scanner.hasNextDouble()) {
double weight = scanner.nextDouble();
System.out.println("體重: " + weight);
} else if (scanner.hasNextBoolean()) {
boolean status = scanner.nextBoolean();
System.out.println("狀態(tài): " + status);
} else {
String name = scanner.next();
System.out.println("姓名: " + name);
}
}
}
2. 靈活的分隔符控制
String csvData = "A,B,C\n1,2,3\nX,Y,Z";
// 使用逗號(hào)作為分隔符
try (Scanner scanner = new Scanner(csvData)) {
scanner.useDelimiter(",|\n"); // 逗號(hào)或換行符作為分隔符
while (scanner.hasNext()) {
String token = scanner.next();
System.out.println("Token: " + token);
}
}
3. 模式匹配(正則表達(dá)式)
String text = "價(jià)格: $25.50, 重量: 1.5kg, 日期: 2023-01-01";
try (Scanner scanner = new Scanner(text)) {
// 查找價(jià)格模式
String pricePattern = "\\$\\d+\\.\\d+";
while (scanner.hasNext(pricePattern)) {
String price = scanner.next(pricePattern);
System.out.println("找到價(jià)格: " + price);
}
// 重置Scanner查找其他模式
scanner = new Scanner(text);
String datePattern = "\\d{4}-\\d{2}-\\d{2}";
if (scanner.hasNext(datePattern)) {
String date = scanner.next(datePattern);
System.out.println("找到日期: " + date);
}
}
4. 區(qū)域設(shè)置和數(shù)字格式
String europeanData = "1.234,56 2.345,67"; // 歐洲數(shù)字格式
try (Scanner scanner = new Scanner(europeanData)) {
scanner.useLocale(Locale.GERMANY); // 使用德國(guó)區(qū)域設(shè)置
while (scanner.hasNextDouble()) {
double number = scanner.nextDouble();
System.out.println("數(shù)字: " + number);
}
}
5. 精確的輸入驗(yàn)證
String input = "123 456 abc 789";
try (Scanner scanner = new Scanner(input)) {
// 精確控制輸入類型
if (scanner.hasNextInt()) {
int first = scanner.nextInt(); // 123
}
if (scanner.hasNextInt()) {
int second = scanner.nextInt(); // 456
}
if (scanner.hasNext("abc")) {
String text = scanner.next(); // abc
}
if (scanner.hasNextInt()) {
int third = scanner.nextInt(); // 789
}
}
與 BufferedReader 的對(duì)比
| 特性 | Scanner | BufferedReader |
|---|---|---|
| 數(shù)據(jù)類型解析 | ? 自動(dòng)解析 int, double, boolean 等 | ? 只能返回 String |
| 分隔符控制 | ? 高度可配置,支持正則表達(dá)式 | ? 固定按行讀取 |
| 模式匹配 | ? 支持正則表達(dá)式模式匹配 | ? 不支持 |
| 區(qū)域設(shè)置 | ? 支持不同地區(qū)的數(shù)字格式 | ? 不支持 |
| 性能 | ? 相對(duì)較慢 | ? 更快 |
| 內(nèi)存使用 | ? 緩沖區(qū)較小 | ? 緩沖區(qū)可配置 |
| 簡(jiǎn)單行讀取 | ? 支持但較慢 | ? 專門優(yōu)化 |
使用場(chǎng)景建議
使用 Scanner 的場(chǎng)景
// 解析結(jié)構(gòu)化數(shù)據(jù)
String studentData = "張三 20 計(jì)算機(jī) 85.5";
try (Scanner scanner = new Scanner(studentData)) {
String name = scanner.next();
int age = scanner.nextInt();
String major = scanner.next();
double score = scanner.nextDouble();
}
// 解析CSV數(shù)據(jù)
String csv = "1,蘋果,5.5\n2,香蕉,3.2";
try (Scanner scanner = new Scanner(csv)) {
scanner.useDelimiter(",|\n");
while (scanner.hasNext()) {
// 按字段解析
}
}
使用 BufferedReader 的場(chǎng)景
// 簡(jiǎn)單逐行讀取大文件
try (BufferedReader reader = new BufferedReader(new FileReader("largefile.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
// 處理每一行
}
}
// 性能要求高的場(chǎng)景
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"), 8192)) {
// 使用更大的緩沖區(qū)
}
什么時(shí)候該用 BufferedReader
只有當(dāng)文本規(guī)模達(dá)到以下程度時(shí)才需要考慮:
- 行數(shù):成千上萬(wàn)行
- 文件大小:幾十MB以上
- 內(nèi)存敏感:在移動(dòng)設(shè)備或內(nèi)存受限環(huán)境
總結(jié)
選擇 Scanner 當(dāng)需要:
- 自動(dòng)數(shù)據(jù)類型轉(zhuǎn)換
- 復(fù)雜的分隔符邏輯
- 正則表達(dá)式模式匹配
- 解析結(jié)構(gòu)化文本數(shù)據(jù)
選擇 BufferedReader 當(dāng)需要:
- 高性能的簡(jiǎn)單行讀取
- 處理大文件
- 最小內(nèi)存占用
- 簡(jiǎn)單的文本處理
對(duì)于你的原始需求(一行一行讀取文本),如果只是簡(jiǎn)單讀取,BufferedReader 性能更好;如果需要解析每行的數(shù)據(jù)內(nèi)容,Scanner 更合適。
以上就是Java實(shí)現(xiàn)一行一行讀取文本的多種方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Java按行讀取文本的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java實(shí)現(xiàn)酷狗音樂臨時(shí)緩存文件轉(zhuǎn)換為MP3文件的方法
這篇文章主要介紹了java實(shí)現(xiàn)酷狗音樂臨時(shí)緩存文件轉(zhuǎn)換為MP3文件的方法,涉及java針對(duì)文件操作的相關(guān)技巧,需要的朋友可以參考下2016-08-08
配置化Feign接口動(dòng)態(tài)切換URL方式
本文介紹了在開發(fā)、測(cè)試和生產(chǎn)環(huán)境中使用Feign接口時(shí),根據(jù)不同的環(huán)境動(dòng)態(tài)切換調(diào)用URL的方法,通過在不同環(huán)境的配置文件中配置URL,并實(shí)現(xiàn)一個(gè)Feign攔截器來讀取這些配置,從而實(shí)現(xiàn)URL的動(dòng)態(tài)切換,這種方法避免了引入過多步驟,同時(shí)也保證了不同環(huán)境下的URL正確調(diào)用2024-11-11
在idea中使用JaCoCo插件統(tǒng)計(jì)單元測(cè)試覆蓋率的實(shí)現(xiàn)
這篇文章主要介紹了在idea中使用JaCoCo插件統(tǒng)計(jì)單元測(cè)試覆蓋率的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-01-01
Dubbo之SPI機(jī)制的實(shí)現(xiàn)原理和優(yōu)勢(shì)分析
這篇文章主要介紹了Dubbo之SPI機(jī)制的實(shí)現(xiàn)原理和優(yōu)勢(shì),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-05-05
File的API和常用方法詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了File的API和常用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05
Java多線程編程小實(shí)例模擬停車場(chǎng)系統(tǒng)
這是一個(gè)關(guān)于Java多線程編程的例子,用多線程的思想模擬停車場(chǎng)管理系統(tǒng),這里分享給大家,供需要的朋友參考。2017-10-10
springboot集成redis啟動(dòng)報(bào)錯(cuò)問題的解決方式
這篇文章主要介紹了springboot集成redis啟動(dòng)報(bào)錯(cuò)問題的解決方式,從錯(cuò)誤信息上看缺少pool2相關(guān)包,查詢資料發(fā)現(xiàn)當(dāng)redis客戶端選擇Lettuce時(shí)候需要增加:commons-pool22023-11-11
添加引用,重啟服務(wù),需要的朋友可以參考下

