use std::fs::File;
use std::io::{BufReader, Chain, Cursor, Read};
use std::path::PathBuf;
pub(crate) struct MultiFileRead {
current: Chain<BufReader<File>, Cursor<Vec<u8>>>,
previous_path: Option<PathBuf>,
current_path: PathBuf,
next: Vec<PathBuf>,
separator: Vec<u8>,
}
impl MultiFileRead {
pub(crate) fn new(files: Vec<PathBuf>, separator: String) -> std::io::Result<Self> {
let separator = separator.as_bytes().to_vec();
let mut files = files;
let first = files.remove(0);
let current = BufReader::new(File::open(&first)?).chain(Cursor::new(separator.clone()));
Ok(Self {
current,
previous_path: None,
current_path: first,
next: files,
separator,
})
}
}
impl Read for MultiFileRead {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let n = self.current.read(buf).map_err(|e| {
std::io::Error::new(
e.kind(),
format!(
"failed while reading file {}: {}",
self.current_path.display(),
e
),
)
})?;
if n == 0 && !self.next.is_empty() {
loop {
if let Some(p) = self.next.pop() {
self.current =
BufReader::new(File::open(&p)?).chain(Cursor::new(self.separator.clone()));
self.previous_path = Some(std::mem::replace(&mut self.current_path, p));
let n = self.current.read(buf).map_err(|e| {
std::io::Error::new(
e.kind(),
format!(
"failed while reading file {}: {}",
self.current_path.display(),
e
),
)
})?;
if n > 0 {
return Ok(n);
}
} else {
return Ok(0);
}
}
}
Ok(n)
}
}