问题描述
我正在从事一个项目,该项目涉及从不同偏移量的文件读取不同信息。
目前,我使用以下代码:
// ------------------------ SECTORS PER CLUSTER ------------------------
// starts at 13
opened_file.seek(SeekFrom::Start(13)).unwrap();
let aux: &mut [u8] = &mut [0; 1];
let _buf = opened_file.read_exact(aux);
// ------------------------ RESERVED SECTORS ------------------------
// starts at 14
opened_file.seek(SeekFrom::Start(14)).unwrap();
let aux: &mut [u8] = &mut [0; 2];
let _buf = opened_file.read_exact(aux);
但是如你所见,我每次都需要创建一个我想读取的大小的新缓冲区,我不能直接将其指定为函数的参数。
我尝试创建一个结构体,但我无法创建我想要的所有不同数据片段的结构体。例如:
struct FileStruct {
a1: &mut [u8] &mut [0; 1],a2: &mut [u8] &mut [0; 2],}
read_exact 方法需要哪些类型才能工作。
有没有更有效的方法可以从文件的不同偏移量读取信息,而不必为我想从文件中读取的每条信息重复复制粘贴这些代码行?某种功能/光标/矢量可以轻松地在偏移量周围移动?以及将这些信息写入结构字段的方法?
提前致谢!
解决方法
最简单的方法是拥有一个拥有数组的结构,然后查找并读入该结构。
use std::io::{self,prelude::*,SeekFrom};
#[derive(Debug,Clone,Default)]
struct FileStruct {
a1: [u8; 1],a2: [u8; 2],}
fn main() -> io::Result<()> {
let mut file_struct: FileStruct = Default::default();
let mut opened_file = unimplemented!(); // open file somehow
opened_file.seek(SeekFrom::Start(13))?;
opened_file.read_exact(&mut file_struct.a1)?;
opened_file.seek(SeekFrom::Start(14))?;
opened_file.read_exact(&mut file_struct.a2)?;
println!("{:?}",file_struct);
Ok(())
}
这仍然是相当重复的,因此您可以创建一个 seek_read
函数来减少重复:
use std::io::{self,}
fn seek_read(mut reader: impl Read + Seek,offset: u64,buf: &mut [u8]) -> io::Result<()> {
reader.seek(SeekFrom::Start(offset))?;
reader.read_exact(buf)?;
Ok(())
}
fn main() -> io::Result<()> {
let mut file_struct: FileStruct = Default::default();
let mut opened_file = unimplemented!(); // open file somehow
seek_read(&mut opened_file,13,&mut file_struct.a1)?;
seek_read(&mut opened_file,14,&mut file_struct.a2)?;
println!("{:?}",file_struct);
Ok(())
}
使用宏可以进一步降低重复次数:
use std::io::{self,}
macro_rules! read_offsets {
($file: ident,$file_struct: ident,[]) => {};
($file: ident,[$offset: expr => $field: ident $(,$offsets: expr => $fields: ident)*]) => {
$file.seek(SeekFrom::Start($offset))?;
$file.read_exact(&mut $file_struct.$field)?;
read_offsets!($file,$file_struct,[$($offsets => $fields),*]);
}
}
fn main() -> io::Result<()> {
let mut file_struct: FileStruct = Default::default();
let mut opened_file = unimplemented!(); // open file somehow
read_offsets!(opened_file,file_struct,[13 => a1,14 => a2]);
println!("{:?}",file_struct);
Ok(())
}
,
这是对 Aplet123 的补充答案:您必须将字节按原样存储到结构中这一点并不十分清楚,因此您还可以分配一个缓冲区(作为固定大小的数组)和用正确大小的切片重用它,例如
{% load static %}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
<section class="content">
{% block content %}
{% endblock %}
</section>
</body>
</html>
您也可以使用 the byteorder crate,它可以让您directly read numbers or sequences of numbers。它基本上只是为您完成不依赖的“创建正确大小的堆栈缓冲区;读取;解码”。
这特别有用,因为它看起来很像“每个集群的扇区”应该是 u8,而“保留扇区”应该是 u16。使用 let mut buf = [0u8;16];
opened_file.read_exact(&mut buf[..4])?; // will read 4 bytes
// do thing with the first 4 bytes
opened_file.read_exact(&mut buf[..8])?; // will read 8 bytes this time
// etc...
,您可以直接 byteorder
或 read_16()
。