usecrate::file::tempfile; use std::fs::File; use std::io::{self, Cursor, Read, Seek, SeekFrom, Write};
/// A wrapper for the two states of a `SpooledTempFile`. #[derive(Debug)] pubenum SpooledData {
InMemory(Cursor<Vec<u8>>),
OnDisk(File),
}
/// An object that behaves like a regular temporary file, but keeps data in /// memory until it reaches a configured size, at which point the data is /// written to a temporary file on disk, and further operations use the file /// on disk. #[derive(Debug)] pubstruct SpooledTempFile {
max_size: usize,
inner: SpooledData,
}
/// Create a new spooled temporary file. /// /// # Security /// /// This variant is secure/reliable in the presence of a pathological temporary /// file cleaner. /// /// # Resource Leaking /// /// The temporary file will be automatically removed by the OS when the last /// handle to it is closed. This doesn't rely on Rust destructors being run, so /// will (almost) never fail to clean up the temporary file. /// /// # Examples /// /// ``` /// use tempfile::spooled_tempfile; /// use std::io::{self, Write}; /// /// # fn main() { /// # if let Err(_) = run() { /// # ::std::process::exit(1); /// # } /// # } /// # fn run() -> Result<(), io::Error> { /// let mut file = spooled_tempfile(15); /// /// writeln!(file, "short line")?; /// assert!(!file.is_rolled()); /// /// // as a result of this write call, the size of the data will exceed /// // `max_size` (15), so it will be written to a temporary file on disk, /// // and the in-memory buffer will be dropped /// writeln!(file, "marvin gardens")?; /// assert!(file.is_rolled()); /// /// # Ok(()) /// # } /// ``` #[inline] pubfn spooled_tempfile(max_size: usize) -> SpooledTempFile {
SpooledTempFile::new(max_size)
}
/// Returns true if the file has been rolled over to disk. #[must_use] pubfn is_rolled(&self) -> bool { matchself.inner {
SpooledData::InMemory(_) => false,
SpooledData::OnDisk(_) => true,
}
}
/// Rolls over to a file on disk, regardless of current size. Does nothing /// if already rolled over. pubfn roll(&mutself) -> io::Result<()> { if !self.is_rolled() { letmut file = tempfile()?; iflet SpooledData::InMemory(cursor) = &mutself.inner {
file.write_all(cursor.get_ref())?;
file.seek(SeekFrom::Start(cursor.position()))?;
} self.inner = SpooledData::OnDisk(file);
}
Ok(())
}
pubfn set_len(&mutself, size: u64) -> Result<(), io::Error> { if size > self.max_size as u64 { self.roll()?; // does nothing if already rolled over
} match &mutself.inner {
SpooledData::InMemory(cursor) => {
cursor.get_mut().resize(size as usize, 0);
Ok(())
}
SpooledData::OnDisk(file) => file.set_len(size),
}
}
/// Consumes and returns the inner `SpooledData` type. #[must_use] pubfn into_inner(self) -> SpooledData { self.inner
}
}
impl Write for SpooledTempFile { fn write(&mutself, buf: &[u8]) -> io::Result<usize> { // roll over to file if necessary if matches! {
&self.inner, SpooledData::InMemory(cursor) if cursor.position().saturating_add(buf.len() as u64) > self.max_size as u64
} { self.roll()?;
}
// write the bytes match &mutself.inner {
SpooledData::InMemory(cursor) => cursor.write(buf),
SpooledData::OnDisk(file) => file.write(buf),
}
}
fn write_vectored(&mutself, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> { if matches! {
&self.inner, SpooledData::InMemory(cursor) // Borrowed from the rust standard library. if bufs
.iter()
.fold(cursor.position(), |a, b| a.saturating_add(b.len() as u64))
> self.max_size as u64
} { self.roll()?;
} match &mutself.inner {
SpooledData::InMemory(cursor) => cursor.write_vectored(bufs),
SpooledData::OnDisk(file) => file.write_vectored(bufs),
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.