rust 将文件拆分为任意N字节切片

vhipe2zx  于 2023-04-12  发布在  其他
关注(0)|答案(4)|浏览(129)

我需要将文件分成N个字节的段。目前,我使用的代码将文件分成固定大小的段(LEN)。然而,我需要使用计算值而不是LEN。问题是let mut slice_buffer = [0u8; LEN];只能使用LEN的常量值,而我不能使用变量。
有没有一种替代方法可以将任意长度的向量块推送到file_slices: Vec<Vec<u8>>,以便file_slices.len() < 255不受文件大小的影响?

let mut file = match File::open(path).unwrap();
    const LEN: usize = 4096;
    let mut file_slices: Vec<Vec<u8>> = Vec::new();
    let mut slice_buffer = [0u8; LEN];
    let mut bytes_in_last_row = 0;

    //slice the file into 4096 byte slices
    let mut end_of_file = false;
    while !end_of_file {
        let bytes_read = file.read(&mut slice_buffer).unwrap();

        if bytes_read != 0 {
            let mut slice_vec: Vec<u8> = Vec::new();
            bytes_in_last_row = bytes_read;
            for i in 0..LEN {
                slice_vec.push(slice_buffer[i]);
            }

            file_slices.push(slice_vec);
            slice_buffer = [0u8; LEN];
        } else {
            end_of_file = true;
        }
    }
    println!("Vector size is {} lines.", file_slices.len());
gcuhipw9

gcuhipw91#

let mut file = Vec::new();
File::open("foo").unwrap().read_to_end(&mut file);
let file_slices: Vec<&[u8]> = file.chunks(256).collect();

这里的file_slicesfile的引用集合。这节省了再次复制整个文件的时间,但意味着只要file_slices存在,就不能删除file
如果你想要一个深拷贝,你可以这样做:

let file_slices: Vec<Vec<u8>> = {
    let mut file = Vec::new();
    File::open("foo").unwrap().read_to_end(&mut file);

    file.chunks(256).map(<[u8]>::to_vec).collect()
};
cyvaqqii

cyvaqqii2#

既然你先读入一个数组,然后把这个数组复制到一个向量中,我建议你直接读入一个向量(长度是可调的,而不是一个常量,正如你所要求的)。
请注意,避免副本是通过与新向量交换(为下一个块做好准备)来完成的。
我尽可能地接近你最初的例子。
在你自己的回答中,你给出了关于最后一部分的细节;我做了相应的调整。
请注意,如果read()不是0(它可能小于请求的数量),则无法保证read()将准确返回chunk_length,即使在文件的中间(不一定在最后)。
如果返回值n小于缓冲区大小,即使读取器还没有到达流的末尾,也不是错误。例如,这可能是因为现在实际可用的字节数较少(例如,接近文件结尾),或者因为read()被信号中断。

use std::io::Read;

fn make_file_slices(
    path: &str,
    chunk_length: usize,
) -> Result<Vec<Vec<u8>>, Box<dyn std::error::Error>> {
    let mut file = std::fs::File::open(path)?;
    let mut file_slices = Vec::new();
    let mut slice_buffer = vec![0_u8; chunk_length];
    let mut bytes_in_last_row = 0;
    loop {
        // read (may-be) incomplete chunk
        let bytes_read = file.read(&mut slice_buffer[bytes_in_last_row..])?;
        if bytes_read == 0 {
            // EOF
            if bytes_in_last_row > 0 {
                // keep the incomplete (zero padded) last chunk
                file_slices.push(slice_buffer);
            }
            break;
        }
        bytes_in_last_row += bytes_read;
        if bytes_in_last_row == chunk_length {
            // the current chunk is complete
            bytes_in_last_row = 0;
            let mut tmp = vec![0_u8; chunk_length];
            std::mem::swap(&mut tmp, &mut slice_buffer);
            file_slices.push(tmp);
        }
    }
    Ok(file_slices)
}

fn main() {
    match make_file_slices("src/main.rs", 12) {
        Ok(file_slices) => {
            println!("Vector size is {} lines.", file_slices.len());
            for (i, s) in file_slices.iter().enumerate() {
                println!("{}: {:?}", i, s);
            }
        }
        Err(e) => {
            println!("Error: {:?}", e);
        }
    }
}
/*
Vector size is 112 lines.
0: [117, 115, 101, 32, 115, 116, 100, 58, 58, 105, 111, 58]
1: [58, 82, 101, 97, 100, 59, 10, 10, 102, 110, 32, 109]
2: [97, 107, 101, 95, 102, 105, 108, 101, 95, 115, 108, 105]
...
109: [114, 58, 32, 123, 58, 63, 125, 34, 44, 32, 101, 41]
110: [59, 10, 32, 32, 32, 32, 32, 32, 32, 32, 125, 10]
111: [32, 32, 32, 32, 125, 10, 125, 10, 0, 0, 0, 0]
*/
8wigbo56

8wigbo563#

使用Veclet slice_buffer = vec![0; LEN],然后truncate它到正确的大小,并把它直接在你的输出:

let mut file = match File::open(path).unwrap();
const LEN: usize = 4096;
let mut file_slices: Vec<Vec<u8>> = Vec::new();
let mut bytes_in_last_row = 0;

//slice the file into 4096 byte slices
let mut end_of_file = false;
while !end_of_file {
    let mut slice = vec![0; LEN];
    let bytes_read = file.read(&mut slice[..]).unwrap();

    if bytes_read != 0 {
        slice.truncate (bytes_read);
        file_slices.push(slice);
    } else {
        end_of_file = true;
    }
}
println!("Vector size is {} lines.", file_slices.len());
klr1opcd

klr1opcd4#

@prog-fh解决方案几乎解决了我的问题。由于它帮助我做到了这一点,我将其标记为“接受”。如果最后一个块的长度小于chunk_length,我的代码将添加零,所以我完全删除了chunk_count并以这种方式简化了循环:

loop {
        // read (may-be) incomplete chunk
        let bytes_read = file.read(&mut slice_buffer[bytes_in_last_row..])?;
        if bytes_read == 0 {
            break; // EOF
        }

        // the current chunk is complete
        bytes_in_last_row = 0;
        let mut tmp = vec![0_u8; chunk_length];
        std::mem::swap(&mut tmp, &mut slice_buffer);
        file_slices.push(tmp);
    }

相关问题