Java實現(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";
// 從字符串讀?。ㄐ枰葘懭肱R時文件)
try {
Path tempFile = Files.createTempFile("temp", ".txt");
Files.write(tempFile, str.getBytes());
Files.lines(tempFile).forEach(System.out::println);
// 清理臨時文件
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);
推薦方案
- 對于字符串:使用
str.lines()(Java 11+) 或split("\n") - 對于文件:使用
Files.lines()(Java 8+) 或BufferedReader - 需要更多控制:使用
Scanner
最簡潔的方式是使用 Java 11 的 lines() 方法:
String str = "A\n" + "B\n" + "C"; str.lines().forEach(System.out::println);
輸出結果:
A
B
C
在 Java 8 環(huán)境下,split("\n") 和 BufferedReader 各有優(yōu)缺點,具體選擇取決于使用場景:
性能對比
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)點:
- 代碼簡潔,一行搞定
- 適合已知內容較小的字符串
- 可以直接得到數(shù)組,方便后續(xù)處理
缺點:
- 一次性加載所有內容到內存,大文本會占用大量內存
- 需要處理尾部的空行問題
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)點:
- 內存效率高,逐行讀取,適合大文件
- 自動處理不同操作系統(tǒng)的換行符(
\n,\r\n,\r) - 統(tǒng)一的接口處理字符串和文件
缺點:
- 代碼相對冗長
- 需要處理異常
推薦選擇
場景 1:小文本,內容已知且不大
// 使用 split("\n")
String[] lines = str.split("\n");
Arrays.stream(lines).forEach(System.out::println);
場景 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();
}
場景 3:Java 8 更優(yōu)雅的寫法
// 結合 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();
}
實際建議
對于你的具體案例:
String str = "A\n" + "B\n" + "C";
// 如果確定文本很小,用 split 更簡潔
String[] lines = str.split("\n");
for (String line : lines) {
System.out.println(line);
}
// 如果要養(yǎng)成好習慣或處理可能的大文本,用 BufferedReader
try (BufferedReader reader = new BufferedReader(new StringReader(str))) {
reader.lines().forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
總結: 對于你當前的小例子,split("\n") 完全足夠且更簡潔。但如果考慮到代碼的可擴展性和健壯性,BufferedReader 是更好的選擇。
Scanner 相比 BufferedReader 提供了更豐富的文本解析功能,主要在數(shù)據(jù)類型解析和分隔符控制方面有優(yōu)勢。
Scanner 的額外控制能力
1. 數(shù)據(jù)類型自動解析
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";
// 使用逗號作為分隔符
try (Scanner scanner = new Scanner(csvData)) {
scanner.useDelimiter(",|\n"); // 逗號或換行符作為分隔符
while (scanner.hasNext()) {
String token = scanner.next();
System.out.println("Token: " + token);
}
}
3. 模式匹配(正則表達式)
String text = "價格: $25.50, 重量: 1.5kg, 日期: 2023-01-01";
try (Scanner scanner = new Scanner(text)) {
// 查找價格模式
String pricePattern = "\\$\\d+\\.\\d+";
while (scanner.hasNext(pricePattern)) {
String price = scanner.next(pricePattern);
System.out.println("找到價格: " + 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ù)字格式
String europeanData = "1.234,56 2.345,67"; // 歐洲數(shù)字格式
try (Scanner scanner = new Scanner(europeanData)) {
scanner.useLocale(Locale.GERMANY); // 使用德國區(qū)域設置
while (scanner.hasNextDouble()) {
double number = scanner.nextDouble();
System.out.println("數(shù)字: " + number);
}
}
5. 精確的輸入驗證
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 的對比
| 特性 | Scanner | BufferedReader |
|---|---|---|
| 數(shù)據(jù)類型解析 | ? 自動解析 int, double, boolean 等 | ? 只能返回 String |
| 分隔符控制 | ? 高度可配置,支持正則表達式 | ? 固定按行讀取 |
| 模式匹配 | ? 支持正則表達式模式匹配 | ? 不支持 |
| 區(qū)域設置 | ? 支持不同地區(qū)的數(shù)字格式 | ? 不支持 |
| 性能 | ? 相對較慢 | ? 更快 |
| 內存使用 | ? 緩沖區(qū)較小 | ? 緩沖區(qū)可配置 |
| 簡單行讀取 | ? 支持但較慢 | ? 專門優(yōu)化 |
使用場景建議
使用 Scanner 的場景
// 解析結構化數(shù)據(jù)
String studentData = "張三 20 計算機 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 的場景
// 簡單逐行讀取大文件
try (BufferedReader reader = new BufferedReader(new FileReader("largefile.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
// 處理每一行
}
}
// 性能要求高的場景
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"), 8192)) {
// 使用更大的緩沖區(qū)
}
什么時候該用 BufferedReader
只有當文本規(guī)模達到以下程度時才需要考慮:
- 行數(shù):成千上萬行
- 文件大小:幾十MB以上
- 內存敏感:在移動設備或內存受限環(huán)境
總結
選擇 Scanner 當需要:
- 自動數(shù)據(jù)類型轉換
- 復雜的分隔符邏輯
- 正則表達式模式匹配
- 解析結構化文本數(shù)據(jù)
選擇 BufferedReader 當需要:
- 高性能的簡單行讀取
- 處理大文件
- 最小內存占用
- 簡單的文本處理
對于你的原始需求(一行一行讀取文本),如果只是簡單讀取,BufferedReader 性能更好;如果需要解析每行的數(shù)據(jù)內容,Scanner 更合適。
以上就是Java實現(xiàn)一行一行讀取文本的多種方法詳解的詳細內容,更多關于Java按行讀取文本的資料請關注腳本之家其它相關文章!
相關文章
解析使用jdbc,hibernate處理clob/blob字段的詳解
本篇是對使用jdbc,hibernate處理clob/blob字段進行了詳細的分析介紹,需要的朋友參考下2013-05-05
springboot訪問template下的html頁面的實現(xiàn)配置
這篇文章主要介紹了springboot訪問template下的html頁面的實現(xiàn)配置,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-12-12
Java中的CopyOnWriteArrayList原理詳解
這篇文章主要介紹了Java中的CopyOnWriteArrayList原理詳解,如源碼所示,CopyOnWriteArrayList和ArrayList一樣,都在內部維護了一個數(shù)組,操作CopyOnWriteArrayList其實就是在操作內部的數(shù)組,需要的朋友可以參考下2023-12-12
controller接口跳轉到另一個controller接口的實現(xiàn)
這篇文章主要介紹了controller接口跳轉到另一個controller接口的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09

