开发者

Java实现一行一行读取文本的多种方法详解

目录
  • 1. 使用 BufferedReader + FileReader
  • 2. 使用 Scanner
  • 3. 使用 Files.lines() (Java 8+)
  • 4. 使用 String 的 split() 方法(适用于字符串)
  • 5. 使用 Lines() 方法 (Java 11+)
  • 推荐方案
  • 性能对比
    • 1.split("\n")- 适用于小文本
    • 2.BufferedReader- 适用于大文本或文件
  • 推荐选择
    • 场景 1:小文本,内容已知且不大
    • 场景 2:大文本或需要处理文件
    • 场景 3:Java 8 更优雅的写法
  • 实际建议
    • Scanner 的额外控制能力
      • 1. 数据类型自动解析
      • 2. 灵活的分隔符控制
      • 3. 模式匹配(正则表达式)
      • 4. 区域设置和数字格式
      • 5. 精确的输入验证
    • 与 BufferedReader 的对比
      • 使用场景建议
        • 使用 Scanner 的场景
        • 使用 BufferedReader 的场景
      • 什么时候该用 BufferedReader
        • 总结

          在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";
          
          //http://www.devze.com 从字符串读取(需要先写入临时文件)
          try {
              Path tempFile = Files.createTempFile("temp", ".txt");
              Files.write(tempFile, str.getBytes());
              
              Files.lines(tempFile).forEach(System.out::println);
              
              // 清理临时文件
              Files.deletephpIfExists(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 环境下,split("\n")BufferedReader 各有优缺点,具体选择取决于使用场景:

          性能对比

          1.split("\n")- 适用于小文本

          String str = "A\n" + "B\n" + "C";
          String[] lines = str.split("\n");
          for (String line : lines) {
              System.out.println(line);
          }
          

          优点:

          • 代码简洁,一行搞定
          • 适合已知内容较小的字符串
          • 可以直接得到数组,方便后续处理

          缺点:

          • 一次性加载所有内容到内存,大文本会占用大量内存
          • 需要处理尾部的空行问题

          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();
          }
          

          优点:

          • 内存效率高,逐行读取,适合大文件
          • 自动处理不同操作系统的换行符(\n, \r\n, \r
          • 统一的接口处理字符串和文件

          缺点:

          • 代码相对冗长
          • 需要处理异常

          推荐选择

          场景 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 更优雅的写法

          // 结合 BufferedReader 和 Stream API
          try (BufferedReader reader = new BphpufferedReader(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);
          }
          
          // 如果要养成好习惯或处理可能的大文本,用 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 提供了更丰富的文本解析功能,主要在数据类型解析和分隔符控制方面有优势。

          Scanner 的额外控制能力

          1. 数据类型自动解析

          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("状态: " + 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. 区域设置和数字格式

          String europeanData = "1.234,56 2.345,67"; // 欧洲数字格式
          
          try (Scanner scanner = new Scanner(europeanData)) {
              scanner.useLocale(Locale.GERMANY); // 使用德国区域设置
              
              while (scanner.hasNextDouble()) {
                  douwww.devze.comble number = scanner.nextDouble();
                  System.out.println("数字: " + 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 的对比

          特性ScannerBufferedReader
          数据类型解析✅ 自动解析 int, double, boolean 等❌ 只能返回 String
          分隔符控制✅ 高度可配置,支持正则表达式❌ 固定按行读取
          模式匹配✅ 支持正则表达式模式匹配❌ 不支持
          区域设置✅ 支持不同地区的数字格式❌ 不支持
          性能❌ 相对较慢✅ 更快
          内存使用❌ 缓冲区较小✅ 缓冲区可配置
          简单行读取✅ 支持但较慢✅ 专门优化

          使用场景建议

          使用 Scanner 的场景

          // 解析结构化数据
          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数据
          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)) {
              // 使用更大的缓冲区
          }
          

          什么时候该用 BufferedReader

          只有当文本规模达到以下程度时才需要考虑:

          • 行数:成千上万行
          • 文件大小:几十MB以上
          • 内存敏感:在移动设备或内存受限环境

          总结

          选择 Scanner 当需要:

          • 自动数据类型转换
          • 复杂的分隔符逻辑
          • 正则表达式模式匹配
          • 解析结构化文本数据

          选择 BufferedReader 当需要:

          • 高性能的简单行读取
          • 处理大文件
          • 最小内存占用
          • 简单的文本处理

          对于你的原始需求(一行一行读取文本),如果只是简单读取,BufferedReader 性能更好;如果需要解析每行的数据内容,Scanner 更合适。

          以上就是Java实现一行一行读取文本的多种方法详解的详细内容,更多关于Java按行读取文本的资料请关注编程客栈(www.devze.com)其它相关文章!

          0

          上一篇:

          下一篇:

          精彩评论

          暂无评论...
          验证码 换一张
          取 消

          最新开发

          开发排行榜