Как связать несколько разных InputStreams в один InputStream
Мне интересно, есть ли какой-нибудь идеоматический способ связать несколько InputStreams с одним непрерывным InputStream в Java (или Scala).
Для этого мне нужно разобрать плоские файлы, которые я загружаю через сеть с FTP-сервера. Я хочу сделать файл [1..N], открыть потоки, а затем объединить их в один поток. Поэтому, когда файл1 подходит к концу, я хочу начать чтение из файла2 и так далее, пока не дойду до конца файлаN.
Мне нужно прочитать эти файлы в определенном порядке, данные поступают из унаследованной системы, которая создает файлы в барах, поэтому данные в одном зависят от данных в другом файле, но я хотел бы обрабатывать их как один непрерывный поток, чтобы упростить мои логический интерфейс домена.
Я обыскал и нашел PipedInputStream, но я не уверен, что это то, что мне нужно. Пример будет полезен.
Ответы
Ответ 1
Это прямо в JDK! Цитирование JavaDoc SequenceInputStream
:
A SequenceInputStream
представляет логическую конкатенацию других входных потоков. Он начинается с упорядоченного набора входных потоков и считывается с первого до тех пор, пока не будет достигнут конец файла, после чего он будет считываться со второго и так далее, пока не будет достигнут конец файла в последнем из содержащихся входных потоков.
Вы хотите объединить произвольное число InputStream
, а SequenceInputStream
принимает только два. Но так как SequenceInputStream
также является InputStream
, вы можете применить его рекурсивно (вложить их):
new SequenceInputStream(
new SequenceInputStream(
new SequenceInputStream(file1, file2),
file3
),
file4
);
... вы поняли идею.
См. также
Ответ 2
Это делается с использованием SequencedInputStream, что прямо на Java, как показывает ответ Томаша Нуркевича. Мне пришлось сделать это несколько раз в проекте недавно, поэтому я добавил немного Scala -y доброту через шаблон "pimp my library".
object StreamUtils {
implicit def toRichInputStream(str: InputStream) = new RichInputStream(str)
class RichInputStream(str: InputStream) {
// a bunch of other handy Stream functionality, deleted
def ++(str2: InputStream): InputStream = new SequenceInputStream(str, str2)
}
}
С этим я могу выполнить последовательность последовательности следующим образом
val mergedStream = stream1++stream2++stream3
или даже
val streamList = //some arbitrary-length list of streams, non-empty
val mergedStream = streamList.reduceLeft(_++_)
Ответ 3
Другое решение: сначала создайте список входного потока, а затем создайте последовательность входных потоков:
List<InputStream> iss = Files.list(Paths.get("/your/path"))
.filter(Files::isRegularFile)
.map(f -> {
try {
return new FileInputStream(f.toString());
} catch (Exception e) {
throw new RuntimeException(e);
}
}).collect(Collectors.toList());
new SequenceInputStream(Collections.enumeration(iss)))
Ответ 4
Вот более элегантное решение с использованием Vector, это специально для Android, но используйте вектор для любой Java
AssetManager am = getAssets();
Vector v = new Vector(Constant.PAGES);
for (int i = 0; i < Constant.PAGES; i++) {
String fileName = "file" + i + ".txt";
InputStream is = am.open(fileName);
v.add(is);
}
Enumeration e = v.elements();
SequenceInputStream sis = new SequenceInputStream(e);
InputStreamReader isr = new InputStreamReader(sis);
Scanner scanner = new Scanner(isr); // or use bufferedReader