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));
Closing streams correctly
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());
}
Using more than two streams
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...
}