fs_utils/
read.rs

1//! Functions to read from files.
2use std::{
3    self, fs,
4    io::{self, Read},
5    path::Path,
6};
7
8/// Reads the first N bytes from a file.
9///
10/// It is equivalent to `head -c limit` *nix utility.
11pub fn head(path: impl AsRef<Path>, limit: usize) -> io::Result<Vec<u8>> {
12    let file_size = fs::metadata(&path)?.len();
13    let file_size: usize = if file_size <= std::usize::MAX as u64 {
14        file_size as usize
15    } else {
16        std::usize::MAX
17    };
18    let (read_buffer_size, read_limit) = if file_size <= limit {
19        (file_size, file_size)
20    } else {
21        (limit, limit)
22    };
23    let mut read_buffer = vec![0; read_buffer_size];
24    fs::File::open(&path)?.read_exact(&mut read_buffer[..read_limit])?;
25    Ok(read_buffer)
26}
27
28/// Reads the first `N` bytes from a file and return them as a string.
29///
30/// It assumes that the file is encoded with UTF-8, so any invalid UTF-8 sequences will be
31/// replaced with `U+FFFD REPLACEMENT CHARACTER`, which looks like this: �, learn more
32/// [here](https://doc.rust-lang.org/std/string/struct.string.html#method.from_utf8_lossy)).
33///
34/// It is equivalent to `head -c limit` *nix utility.
35pub fn head_to_string(path: impl AsRef<Path>, limit: usize) -> io::Result<String> {
36    Ok(String::from_utf8_lossy(&head(path, limit)?).into_owned())
37}
38
39/// Reads the first `N` bytes from a file and return them as a string. If the file size is greater
40/// than `N` bytes, the truncation message will be put at the end of the String.
41///
42/// It assumes that the file is encoded with UTF-8, so any invalid UTF-8 sequences will be
43/// replaced with `U+FFFD REPLACEMENT CHARACTER`, which looks like this: �, learn more
44/// [here](https://doc.rust-lang.org/std/string/struct.string.html#method.from_utf8_lossy)).
45pub fn head_to_string_with_message(
46    path: impl AsRef<Path>,
47    limit: usize,
48    truncation_message: &str,
49) -> io::Result<String> {
50    let mut read_buffer = head(path, limit + 1)?;
51    if read_buffer.len() > limit {
52        read_buffer[(limit - truncation_message.len())..limit]
53            .copy_from_slice(truncation_message.as_bytes());
54    }
55    read_buffer.truncate(limit);
56    Ok(String::from_utf8_lossy(&read_buffer).into_owned())
57}