JDK8:用java.nio.file.Files.lines方法读取大型文件

先说结论:

如果要读取一个大文件(文件大小超过了内存大小),则可以考虑使用java.nio.file.Files.lines方法来读取这个大型文件的内容。

关于java.nio.file.Files类中lines方法的说明:

 jdk1.8.0_311中原码部分:

    /**
     * Read all lines from a file as a {@code Stream}. Unlike {@link
     * #readAllLines(Path, Charset) readAllLines}, this method does not read
     * all lines into a {@code List}, but instead populates lazily as the stream
     * is consumed.
     *
     * <p> Bytes from the file are decoded into characters using the specified
     * charset and the same line terminators as specified by {@code
     * readAllLines} are supported.
     *
     * <p> After this method returns, then any subsequent I/O exception that
     * occurs while reading from the file or when a malformed or unmappable byte
     * sequence is read, is wrapped in an {@link UncheckedIOException} that will
     * be thrown from the
     * {@link java.util.stream.Stream} method that caused the read to take
     * place. In case an {@code IOException} is thrown when closing the file,
     * it is also wrapped as an {@code UncheckedIOException}.
     *
     * <p> The returned stream encapsulates a {@link Reader}.  If timely
     * disposal of file system resources is required, the try-with-resources
     * construct should be used to ensure that the stream's
     * {@link Stream#close close} method is invoked after the stream operations
     * are completed.
     *
     *
     * @param   path
     *          the path to the file
     * @param   cs
     *          the charset to use for decoding
     *
     * @return  the lines from the file as a {@code Stream}
     *
     * @throws  IOException
     *          if an I/O error occurs opening the file
     * @throws  SecurityException
     *          In the case of the default provider, and a security manager is
     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
     *          method is invoked to check read access to the file.
     *
     * @see     #readAllLines(Path, Charset)
     * @see     #newBufferedReader(Path, Charset)
     * @see     java.io.BufferedReader#lines()
     * @since   1.8
     */
    public static Stream<String> lines(Path path, Charset cs) throws IOException {
        BufferedReader br = Files.newBufferedReader(path, cs);
        try {
            return br.lines().onClose(asUncheckedRunnable(br));
        } catch (Error|RuntimeException e) {
            try {
                br.close();
            } catch (IOException ex) {
                try {
                    e.addSuppressed(ex);
                } catch (Throwable ignore) {}
            }
            throw e;
        }
    }

    /**
     * Read all lines from a file as a {@code Stream}. Bytes from the file are
     * decoded into characters using the {@link StandardCharsets#UTF_8 UTF-8}
     * {@link Charset charset}.
     *
     * <p> This method works as if invoking it were equivalent to evaluating the
     * expression:
     * <pre>{@code
     * Files.lines(path, StandardCharsets.UTF_8)
     * }</pre>
     *
     * @param   path
     *          the path to the file
     *
     * @return  the lines from the file as a {@code Stream}
     *
     * @throws  IOException
     *          if an I/O error occurs opening the file
     * @throws  SecurityException
     *          In the case of the default provider, and a security manager is
     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
     *          method is invoked to check read access to the file.
     *
     * @since 1.8
     */
    public static Stream<String> lines(Path path) throws IOException {
        return lines(path, StandardCharsets.UTF_8);
    }

 从javadoc注解中可以看出,它将文件中的所有行作为 Stream 读取,与 readAllLines 不同,此方法不会将所有行读入 List 中(不全部加载到内存中),而是在流被使用时延迟填充(populates lazily)

java.nio.file.Files 类中的 lines 方法是 Java 8 引入的一个非常有用的方法,用于处理文件和目录的 I/O 操作,它提供了一种流式(Stream-based)的方式来读取文件内容,并将文件的每一行作为字符串(String)对象进行处理。

lines(Path path)方法使用默认字符集(通常是 UTF-8)来解码文件中的字节。

使用场景:

  1. 文本文件处理:当你需要读取和处理大量文本文件时,lines 方法可以方便地按行处理文件内容。
  2. 数据分析和转换:如果你需要对文件中的数据进行分析或转换,可以将 lines 方法返回的 Stream 对象与其他 Stream 操作(如 mapfilterreduce 等)结合使用。
  3. 日志处理:对于日志文件的分析和监控,lines 方法可以方便地读取日志文件并按行进行处理。
  4. 批量文本操作:对于需要批量处理文本文件的场景(如批量重命名、查找和替换等),lines 方法可以提供一个高效且简洁的解决方案。

优缺点:

优点

  1. 简洁性:与传统的文件读取方式相比,lines 方法更加简洁和直观。
  2. 流式处理:与 Stream API 紧密集成,使得文件处理更加灵活和高效。
  3. 内存效率默认情况下,lines 方法使用懒加载(lazy loading)方式读取文件内容,这意味着它不会一次性加载整个文件到内存中,从而减少了内存使用。

缺点

  1. 字符集问题lines 方法默认使用系统默认字符集来解码文件内容。如果文件使用了非默认字符集(如 ISO-8859-1),则需要手动指定字符集,否则可能会出现乱码问题。
  2. 错误处理:与 BufferedReader 或 Scanner 相比,lines 方法在处理文件读取错误时可能不太直观。你需要使用 try-catch 块来捕获和处理可能发生的 IOException
  3. 性能考虑:虽然 lines 方法在大多数情况下都足够高效,但在处理大文件时,由于它使用 Stream API,可能会增加一些额外的开销。此外,如果你需要多次读取同一文件或进行大量的小文件读取操作,使用传统的文件读取方式可能会更加高效。

示例代码:

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class FilesTest {
    public static void main(String[] args) {
        String filePath = "page\example.txt";
        // 使用默认字符编码读取文件的每一行
        try (Stream<String> lines = Files.lines(Paths.get(filePath))) {
            lines.forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();

        }
        // 使用指定的字符编码读取文件的每一行
        try (Stream<String> lines = Files.lines(Paths.get(filePath), StandardCharsets.UTF_8)) {
            lines.forEach(System.out::println);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

所以,如果之后遇到需要读取大型文件的内容进行处理又担心内存不足问题时,可以考虑使用Files.lines方法来进行处理哦~~~,它是在jdk1.8中引入的

Java 中,可以从文件中逐行读取内容。常用的方式有多种,其中最简单的一种是使用 `BufferedReader` 配合 `FileReader` 或者 `Files.lines()` 方法。 以下是基于 `BufferedReader` 的例子: ```java import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class ReadFileExample { public static void main(String[] args) { String filePath = "example.txt"; // 文件路径 try (BufferedReader br = new BufferedReader(new FileReader(filePath))) { String line; while ((line = br.readLine()) != null) { System.out.println(line); // 打印每一行的内容 } } catch (IOException e) { e.printStackTrace(); } } } ``` 在这个程序里: 1. 创建了一个 `BufferedReader` 实例用于高效地读取大块的数据。 2. 使用循环不断调用其 `readLine()` 方法直到返回的是空值(null),这表明已经到达了文件末尾(EOF)。 3. 每次迭代都会打印当前读出的一整行文字至标准输出设备(即屏幕)上。 对于较新的 JDK 版本(JDK 7 及以上),推荐利用 try-with-resources 结构自动管理资源关闭问题,就像上述代码那样做即可避免忘记显式关掉流导致的问题发生风险。 另外一种简洁现代的方法则是借助 NIO.2 API 提供的功能: ```java import java.nio.file.Files; import java.nio.file.Paths; import java.util.stream.Stream; public class ReadFileLinesExample { public static void main(String[] args){ try(Stream<String> stream= Files.lines(Paths.get("path/to/file")) ){ stream.forEach(System.out::println); }catch(Exception ex){ex.printStackTrace();} } } ``` 此段落展示了如何运用 `Files.lines(Path)` 来获取整个文件的所有行作为 Stream 序列然后逐一操作他们。注意这种方式内部仍然实现了缓冲机制所以性能不会差太多同时又具备函数式的风格表达更加紧凑直观易于理解维护修改等优点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值