Skip to content

Commit

Permalink
fs: read/write_at for unix & seek_read/write for win
Browse files Browse the repository at this point in the history
  • Loading branch information
SteveLauC committed Mar 27, 2024
1 parent ba4c86a commit 9ca599d
Showing 1 changed file with 136 additions and 18 deletions.
154 changes: 136 additions & 18 deletions tokio/src/fs/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,10 +539,35 @@ impl File {
self.max_buf_size = max_buf_size;
}

/// Reads a number of bytes starting from a given offset, returns the number
/// of bytes.
/// Reads a number of bytes starting from a given offset.
///
/// Returns the number of bytes read.
///
/// The offset is relative to the start of the file and thus independent
/// from the current cursor.
///
/// The current file cursor is not affected by this function.
///
/// It is not an error to return with a short read.
///
/// # Examples
///
/// ```no_run
/// use tokio::fs::File;
/// use tokio::io::AsyncSeekExt;
///
/// # async fn dox() -> std::io::Result<()> {
/// let mut buf = vec![0_u8; 10];
/// let mut file = File::open("foo.txt").await?;
/// file.read_at(&mut buf, 5).await?;
///
/// assert_eq!(file.stream_position().await.unwrap(), 0);
/// # Ok(())
/// # }
/// ```
#[cfg(unix)]
#[cfg_attr(docsrs, doc(cfg(unix)))]
pub async fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
#[cfg(unix)]
fn _read_at(std: &StdFile, n: usize, offset: u64) -> io::Result<Vec<u8>> {
use std::os::unix::fs::FileExt;
let mut buf: Vec<u8> = vec![0; n];
Expand All @@ -551,7 +576,83 @@ impl File {

Ok(buf)
}
#[cfg(windows)]

let std = self.std.clone();
let n = buf.len();
let bytes_read = asyncify(move || _read_at(&std, n, offset)).await?;
let len = bytes_read.len();
buf[..len].copy_from_slice(&bytes_read);

Ok(len)
}

/// Writes a number of bytes starting from a given offset.
///
/// Returns the number of bytes written.
///
/// The offset is relative to the start of the file and thus independent from
/// the current cursor.
///
/// The current file cursor is not affected by this function.
///
/// When writing beyond the end of the file, the file is appropriately
/// extended and the intermediate bytes are initialized with the value 0.
///
/// It is not an error to return a short write.
///
/// # Examples
///
/// ```no_run
/// use tokio::fs::File;
/// use tokio::io::AsyncSeekExt;
///
/// # async fn dox() -> std::io::Result<()> {
/// let mut file = File::open("foo.txt").await?;
/// file.write_at(b"foo", 5).await?;
///
/// assert_eq!(file.stream_position().await.unwrap(), 0);
/// # Ok(())
/// # }
/// ```
#[cfg(unix)]
#[cfg_attr(docsrs, doc(cfg(unix)))]
pub async fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
use std::os::unix::fs::FileExt;

let std = self.std.clone();
let buf_clone = buf.to_vec();
asyncify(move || std.write_at(&buf_clone, offset)).await
}

/// Seeks to a given position and reads a number of bytes.
///
/// Returns the number of bytes read.
///
/// The offset is relative to the start of the file and thus independent from
/// the current cursor. The current cursor is affected by this function, it
/// is set to the end of the read.
///
/// Reading beyond the end of the file will always return with a length of 0.
///
/// It is not an error to return with a short read. When returning from
/// such a short read, the file pointer is still updated.
///
/// # Examples
///
/// ```no_run
/// use tokio::fs::File;
/// use tokio::io::AsyncSeekExt;
///
/// # async fn dox() -> std::io::Result<()> {
/// let mut file = File::open("foo.txt").await?;
/// let mut buf = vec![0_u8; 10];
/// file.seek_read(&mut buf, 5).await?;
/// # Ok(())
/// # }
/// ```
#[cfg(windows)]
#[cfg_attr(docsrs, doc(cfg(windows)))]
pub async fn seek_read(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
fn _read_at(std: &StdFile, n: usize, offset: u64) -> io::Result<Vec<u8>> {
use std::os::windows::fs::FileExt;
let mut buf: Vec<u8> = vec![0; n];
Expand All @@ -570,23 +671,40 @@ impl File {
Ok(len)
}

/// Writes a number of bytes starting from a given offset, returns the number
/// of bytes written.
pub async fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
#[cfg(unix)]
fn _write_at(std: &StdFile, buf: &[u8], offset: u64) -> io::Result<usize> {
use std::os::unix::fs::FileExt;
std.write_at(buf, offset)
}
#[cfg(windows)]
fn _write_at(std: &StdFile, buf: &[u8], offset: u64) -> io::Result<usize> {
use std::os::windows::fs::FileExt;
std.seek_write(buf, offset)
}
/// Seeks to a given position and writes a number of bytes.
///
/// Returns the number of bytes written.
///
/// The offset is relative to the start of the file and thus independent from
/// the current cursor. The current cursor is affected by this function, it
/// is set to the end of the write.
///
/// When writing beyond the end of the file, the file is appropriately
/// extended and the intermediate bytes are set to zero.
///
/// It is not an error to return a short write. When returning from such a
/// short write, the file pointer is still updated.
///
/// # Examples
///
/// ```no_run
/// use tokio::fs::File;
/// use tokio::io::AsyncSeekExt;
///
/// # async fn dox() -> std::io::Result<()> {
/// let mut file = File::open("foo.txt").await?;
/// file.seek_write(b"foo", 5).await?;
/// # Ok(())
/// # }
/// ```
#[cfg(windows)]
#[cfg_attr(docsrs, doc(cfg(windows)))]
pub async fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
use std::os::windows::fs::FileExt;

let std = self.std.clone();
let buf_clone = buf.to_vec();
asyncify(move || _write_at(&std, &buf_clone, offset)).await
asyncify(move || std.seek_write(&buf_clone, offset)).await
}
}

Expand Down

0 comments on commit 9ca599d

Please sign in to comment.