Reputation: 1000
So i´m able to read out of an existing file like this:
File file = new File("C:\\Something/test.txt");
FileInputStream fis = new FileInputStream(file);
BufferedReader bfr = new BufferedReader(new InputStreamReader(fis));
Now i´m able to use bfr.readLine() and read line by line. If i wanted to read out of another file, do i have to create a new BufferedReader or is there any way to read out of multiple files with one BufferedReader?
Upvotes: 2
Views: 1378
Reputation: 11835
You could use SequenceInputStream
to read files sequentially.
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));
To close these two streams (and reader), just use 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());
}
If there are more than two streams, we'd have to use the constructor that accepts Enumeration
of InputStream
s. The tricky part here, as mentioned by @Boris the Spider, is closing all the streams correctly. We could create an Autoclosable
that would contain all the InputStream
s to close, but then, before we construct that container, but after some of the streams were already constructed, an exception could occur, so some streams would remain unclosed.
A clean way is to include all the streams explicitly in try-with-resources
statement:
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
}
IteratorEnumeration
is the one suggested in https://stackoverflow.com/a/7086010/7637120
Another option is to manually track a list of input streams that were already opened successfully and close them if construction of next stream fails.
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...
}
Upvotes: 3