Io 如何从Rust中的文件读取结构?
有没有一种方法可以直接从Rust中的文件读取结构?我的代码是:Io 如何从Rust中的文件读取结构?,io,rust,Io,Rust,有没有一种方法可以直接从Rust中的文件读取结构?我的代码是: use std::fs::File; struct Configuration { item1: u8, item2: u16, item3: i32, item4: [char; 8], } fn main() { let file = File::open("config_file").unwrap(); let mut config: Configuration;
use std::fs::File;
struct Configuration {
item1: u8,
item2: u16,
item3: i32,
item4: [char; 8],
}
fn main() {
let file = File::open("config_file").unwrap();
let mut config: Configuration;
// How to read struct from file?
}
如何从文件中将配置直接读入config
?这可能吗 给你:
use std::io::Read;
use std::mem;
use std::slice;
#[repr(C, packed)]
#[derive(Debug, Copy, Clone)]
struct Configuration {
item1: u8,
item2: u16,
item3: i32,
item4: [char; 8],
}
const CONFIG_DATA: &[u8] = &[
0xfd, // u8
0xb4, 0x50, // u16
0x45, 0xcd, 0x3c, 0x15, // i32
0x71, 0x3c, 0x87, 0xff, // char
0xe8, 0x5d, 0x20, 0xe7, // char
0x5f, 0x38, 0x05, 0x4a, // char
0xc4, 0x58, 0x8f, 0xdc, // char
0x67, 0x1d, 0xb4, 0x64, // char
0xf2, 0xc5, 0x2c, 0x15, // char
0xd8, 0x9a, 0xae, 0x23, // char
0x7d, 0xce, 0x4b, 0xeb, // char
];
fn main() {
let mut buffer = CONFIG_DATA;
let mut config: Configuration = unsafe { mem::zeroed() };
let config_size = mem::size_of::<Configuration>();
unsafe {
let config_slice = slice::from_raw_parts_mut(&mut config as *mut _ as *mut u8, config_size);
// `read_exact()` comes from `Read` impl for `&[u8]`
buffer.read_exact(config_slice).unwrap();
}
println!("Read structure: {:#?}", config);
}
使用std::io::Read;
使用std::mem;
使用std::slice;
#[报告员(C、C)]
#[派生(调试、复制、克隆)]
结构配置{
第1项:u8,
项目2:u16,
项目3:i32,
第4项:[字符;8],
}
常量配置数据:&[u8]=&[
0xfd,//u8
0xb4,0x50,//u16
0x45,0xcd,0x3c,0x15,//i32
0x71、0x3c、0x87、0xff、//字符
0xe8、0x5d、0x20、0xe7、//字符
0x5f、0x38、0x05、0x4a、//字符
0xc4、0x58、0x8f、0xdc、//字符
0x67,0x1d,0xb4,0x64,//字符
0xf2、0xc5、0x2c、0x15、//字符
0xd8、0x9a、0xae、0x23、//字符
0x7d、0xce、0x4b、0xeb、//字符
];
fn main(){
让mut buffer=CONFIG_DATA;
让mut-config:Configuration=unsafe{mem::zeroed()};
让config_size=mem::size_of::();
不安全{
让config_slice=slice::from_raw_parts_mut(&mut config as*mut u as*mut u8,config_size);
//'read_exact()'来自'read'impl for`&[u8]`
buffer.read_exact(config_slice).unwrap();
}
println!(“读取结构:{:#?}”,配置);
}
(更新了锈1.38)
然而,您需要小心,因为不安全的代码是不安全的。调用slice::from_raw\u parts_mut()
后,同一数据同时存在两个可变句柄,这违反了锈迹别名规则。因此,您可能希望在尽可能短的时间内保持在结构之外创建的可变切片。我还假设您知道endianness问题——上面的代码绝不是可移植的,如果在不同类型的机器上编译和运行(例如ARM和x86),将返回不同的结果
<>如果你可以选择格式,你需要一个紧凑的二进制格式,考虑使用。否则,如果您需要(例如)解析某些预定义的二进制结构,则可以使用crate。以下代码不考虑任何或任何问题,旨在与一起使用<代码>结构配置在这种情况下应该是安全的
下面是一个可以从文件中读取结构(POD类型)的函数:
use std::io::{self, Read};
use std::slice;
fn read_struct<T, R: Read>(mut read: R) -> io::Result<T> {
let num_bytes = ::std::mem::size_of::<T>();
unsafe {
let mut s = ::std::mem::uninitialized();
let buffer = slice::from_raw_parts_mut(&mut s as *mut T as *mut u8, num_bytes);
match read.read_exact(buffer) {
Ok(()) => Ok(s),
Err(e) => {
::std::mem::forget(s);
Err(e)
}
}
}
}
// use
// read_struct::<Configuration>(reader)
因为,使用通常是最好的解决方案。通过这种方式,您可以解决端点问题,不必处理任何不安全的代码,也不必担心对齐或填充:
use byteorder::{LittleEndian, ReadBytesExt}; // 1.2.7
use std::{
fs::File,
io::{self, Read},
};
struct Configuration {
item1: u8,
item2: u16,
item3: i32,
}
impl Configuration {
fn from_reader(mut rdr: impl Read) -> io::Result<Self> {
let item1 = rdr.read_u8()?;
let item2 = rdr.read_u16::<LittleEndian>()?;
let item3 = rdr.read_i32::<LittleEndian>()?;
Ok(Configuration {
item1,
item2,
item3,
})
}
}
fn main() {
let file = File::open("/dev/random").unwrap();
let config = Configuration::from_reader(file);
// How to read struct from file?
}
使用字节顺序::{LittleEndian,ReadBytesExt};//1.2.7
使用std::{
fs::文件,
io::{self,Read},
};
结构配置{
第1项:u8,
项目2:u16,
项目3:i32,
}
impl配置{
fn来自_读取器(mut-rdr:impl-Read)->io::Result{
设item1=rdr.read_u8()?;
设item2=rdr.read_u16::()?;
设item3=rdr.read_i32::()?;
Ok(配置{
项目1,
项目2,
项目3,
})
}
}
fn main(){
让file=file::open(“/dev/random”).unwrap();
让config=Configuration::from_reader(文件);
//如何从文件中读取结构?
}
出于以下几个原因,我忽略了[char;8]
:
char
是32位类型,不清楚您的文件是否具有实际的Unicode码点或C样式的8位值你的文件有什么格式?正确答案很大程度上取决于文件中的实际数据表示形式。@VladimirMatveev二进制格式,我不想从文件中读取并复制到我的结构中;我想用我的结构作为缓冲区来读取文件。啊,我现在明白你需要什么了。如果没有一些不安全的代码,你就做不到。我现在试着写概念证明。这个板条箱似乎正是你想要的:是的,我知道endian的问题-但它只是我正在写的一个快速工具,可以在大约3台计算机上运行。@a.B.,我相信。它现在已经定位了。我使用了'mem::uninitialized',而不是最后的
mem::zeroed
。如果内存仍将被覆盖,那么将其初始化为0似乎没有多大意义。这会给我一条“警告,此警告将成为错误”消息,虽然此代码的总体轮廓很好,但此特定实例违反了Rust的安全性。字符数据的值无效,并且超出了当前支持的字符边界。为什么::std::mem。。。而不是std::mem?有什么区别吗?以:
开头的路径是绝对路径。如果将函数放在模块上,使用绝对路径将确保代码能够编译。搜索absolute in以了解更多信息。谢谢Malbarbow为什么这里需要a::std::mem::forget?这不是表示内存泄漏吗?@Knight用于防止析构函数在s
上运行(s
未初始化)。这是文档中描述的一个用例。我想这些read_u8
和其他read_X
调用可能会调用系统调用。所以它可能不是很有效。我们能以某种尾数而不是整数类型的小部分来读取整个结构吗?@VictorPolevoy这是缓冲读取器要修复的工作。请参阅,从“缓冲I/O”开始。但是是的,您可以不安全地获取任何随机的字节块,并将其转换为任何给定的类型。这就是这里另外两个答案的重点。如果我想读取10GB文件怎么办?性能惩罚将很高。使用原始零件是IMO的唯一方法。@mishmashru我不明白为什么它的性能会比原始零件的性能低。这不需要你有什么意见。编写这两个代码并对其进行基准测试,这样您就可以确定了。
use byteorder::{LittleEndian, ReadBytesExt}; // 1.2.7
use std::{
fs::File,
io::{self, Read},
};
struct Configuration {
item1: u8,
item2: u16,
item3: i32,
}
impl Configuration {
fn from_reader(mut rdr: impl Read) -> io::Result<Self> {
let item1 = rdr.read_u8()?;
let item2 = rdr.read_u16::<LittleEndian>()?;
let item3 = rdr.read_i32::<LittleEndian>()?;
Ok(Configuration {
item1,
item2,
item3,
})
}
}
fn main() {
let file = File::open("/dev/random").unwrap();
let config = Configuration::from_reader(file);
// How to read struct from file?
}