首页 > 解决方案 > 用一个 BufferedReader 读取多个文件?

问题描述

所以我能够像这样读取现有文件:

    File file = new File("C:\\Something/test.txt");
    FileInputStream fis = new FileInputStream(file);
    BufferedReader bfr = new BufferedReader(new InputStreamReader(fis));

现在我可以使用 bfr.readLine() 并逐行读取。如果我想读取另一个文件,我是否必须创建一个新的 BufferedReader 或者有什么方法可以使用一个 BufferedReader 读取多个文件?

标签: java

解决方案


您可以使用SequenceInputStream顺序读取文件。

File file1 = new File("C:\\Something/test1.txt");
File file2 = new File("C:\\Something/test2.txt");
FileInputStream fis1 = new FileInputStream(file1);
FileInputStream fis2 = new FileInputStream(file2);
SequenceInputStream is = new SequenceInputStream(fis1, fis2);
BufferedReader bfr = new BufferedReader(new InputStreamReader(is));

正确关闭流

要关闭这两个流(和阅读器),只需使用try-with-resources

    try (
            FileInputStream fis1 = new FileInputStream(file1);
            FileInputStream fis2 = new FileInputStream(file2);
            SequenceInputStream is = new SequenceInputStream(fis1, fis2);
            BufferedReader bfr = new BufferedReader(new InputStreamReader(is))
    ) {
        System.out.println(bfr.readLine());
        System.out.println(bfr.readLine());
    }

使用两个以上的流

如果有两个以上的流,我们必须使用接受sEnumeration的构造函数。InputStream正如@Boris the Spider 所提到的,这里的棘手部分是正确关闭所有流。我们可以创建一个Autoclosable包含所有InputStream要关闭的 s 的容器,但是在我们构造该容器之前,但在一些流已经构造之后,可能会发生异常,因此一些流将保持未关闭状态。

一种干净的方法是在try-with-resources语句中明确包含所有流:

    try (
            FileInputStream fis1 = new FileInputStream(file1);
            FileInputStream fis2 = new FileInputStream(file2);
            FileInputStream fis3 = new FileInputStream(file3);
            ...
            SequenceInputStream is = new SequenceInputStream(new IteratorEnumeration<>(Arrays.asList(fis1, fis2, fis3, ...).iterator()));
            BufferedReader bfr = new BufferedReader(new InputStreamReader(is))
    ) {
        // .. read from bfr
    }

IteratorEnumerationhttps://stackoverflow.com/a/7086010/7637120中建议的

另一种选择是手动跟踪已成功打开的输入流列表,并在下一个流构建失败时关闭它们。

public class InputStreams implements AutoCloseable {
    private final List<InputStream> streams = new ArrayList<>();

    public List<InputStream> getStreams() {
        return streams;
    }

    public void add(InputStream is) {
        streams.add(is);
    }

    @Override
    public void close() throws IOException {
        IOException firstException = null;
        for (InputStream stream : streams) {
            try {
                stream.close();
            } catch (IOException e) {
                if (firstException == null) {
                    firstException = e;
                } else {
                    firstException.addSuppressed(e);
                }
            }
        }
        if (firstException != null) {
            throw firstException;
        }
    }
}

InputStreams streams = new InputStreams();
while (moreStreams()) {
    InputStream nextStream = null;
    try {
        nextStream = getNextStream();
        streams.add(nextStream);
    } catch (IOException e) {
        // the following will close nextStream and all the earlier streams
        try (InputStreams streamsToClose = streams) {
            if (nextStream != null) {
                nextStream.close();
            }
        } finally {
            throw e;
        }
    }
}

try (
    InputStreams streamsToClose = streams;
    SequenceInputStream is = new SequenceInputStream(new IteratorEnumeration<>(streams.getStreams().iterator()));
    BufferedReader bfr = new BufferedReader(new InputStreamReader(is))
) {
    // work with bfr...
}

推荐阅读