Rust语言从入门到精通系列 - 二进制自压缩序列化bincode模块
Bincode 是一个用于 Rust 语言的二进制编码库,用于将 Rust 结构体序列化为二进制格式,或者将二进制格式反序列化为 Rust 结构体。它支持大多数 Rust 原生类型和自定义类型,并且可以高效地处理大型数据结构。Bincode 还支持压缩和解压缩,以减小序列化后的数据大小。
基础用法
序列化和反序列化一个简单的结构体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use bincode::{serialize, deserialize};
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Person {
name: String,
age: u8,
}
fn main() {
let person = Person {
name: "Alice".to_string(),
age: 25,
};
// Serialize
let encoded: Vec<u8> = serialize(&person).unwrap();
// Deserialize
let decoded: Person = deserialize(&encoded[..]).unwrap();
assert_eq!(person, decoded);
}
在这个示例中,我们定义了一个Person
结构体,它有一个name
字段和一个age
字段。我们将其序列化为一个字节数组,然后将其反序列化回Person
结构体,并将其与原始结构体进行比较。
序列化和反序列化一个嵌套结构体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
use bincode::{serialize, deserialize};
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Address {
street: String,
city: String,
zip: String,
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Person {
name: String,
age: u8,
address: Address,
}
fn main() {
let person = Person {
name: "Alice".to_string(),
age: 25,
address: Address {
street: "123 Main St".to_string(),
city: "Anytown".to_string(),
zip: "12345".to_string(),
},
};
// Serialize
let encoded: Vec<u8> = serialize(&person).unwrap();
// Deserialize
let decoded: Person = deserialize(&encoded[..]).unwrap();
assert_eq!(person, decoded);
}
这个示例中,我们定义了一个Person
结构体,它包含一个嵌套的Address
结构体。我们将其序列化为一个字节数组,然后将其反序列化回Person
结构体,并将其与原始结构体进行比较。
序列化和反序列化一个向量
1
2
3
4
5
6
7
8
9
10
11
12
13
use bincode::{serialize, deserialize};
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
// Serialize
let encoded: Vec<u8> = serialize(&numbers).unwrap();
// Deserialize
let decoded: Vec<i32> = deserialize(&encoded[..]).unwrap();
assert_eq!(numbers, decoded);
}
在这个示例中,我们定义了一个包含整数的向量。我们将其序列化为一个字节数组,然后将其反序列化回一个整数向量,并将其与原始向量进行比较。
序列化和反序列化一个哈希表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use std::collections::HashMap;
use bincode::{serialize, deserialize};
fn main() {
let mut map = HashMap::new();
map.insert("Alice", 25);
map.insert("Bob", 30);
map.insert("Charlie", 35);
// Serialize
let encoded: Vec<u8> = serialize(&map).unwrap();
// Deserialize
let decoded: HashMap<&str, i32> = deserialize(&encoded[..]).unwrap();
assert_eq!(map, decoded);
}
在这个示例中,我们定义了一个包含键值对的哈希表。我们将其序列化为一个字节数组,然后将其反序列化回一个哈希表,并将其与原始哈希表进行比较。
序列化和反序列化一个枚举
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
use bincode::{serialize, deserialize};
#[derive(Serialize, Deserialize, Debug, PartialEq)]
enum Color {
Red,
Green,
Blue,
}
fn main() {
let color = Color::Green;
// Serialize
let encoded: Vec<u8> = serialize(&color).unwrap();
// Deserialize
let decoded: Color = deserialize(&encoded[..]).unwrap();
assert_eq!(color, decoded);
}
在这个示例中,我们定义了一个枚举类型Color
,它有三个可能的值。我们将其序列化为一个字节数组,然后将其反序列化回一个Color
枚举,并将其与原始枚举进行比较。
序列化和反序列化一个字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
use bincode::{serialize, deserialize};
fn main() {
let message = "Hello, world!".to_string();
// Serialize
let encoded: Vec<u8> = serialize(&message).unwrap();
// Deserialize
let decoded: String = deserialize(&encoded[..]).unwrap();
assert_eq!(message, decoded);
}
在这个示例中,我们定义了一个字符串。我们将其序列化为一个字节数组,然后将其反序列化回一个字符串,并将其与原始字符串进行比较。
压缩和解压缩序列化后的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use bincode::{serialize, deserialize, config};
use flate2::{Compression, read::DeflateEncoder, write::DeflateDecoder};
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
// Serialize
let encoded: Vec<u8> = serialize(&numbers).unwrap();
// Compress
let mut compressed = Vec::new();
let mut encoder = DeflateEncoder::new(&encoded[..], Compression::default());
encoder.read_to_end(&mut compressed).unwrap();
// Decompress
let mut decompressed = Vec::new();
let mut decoder = DeflateDecoder::new(&compressed[..]);
decoder.read_to_end(&mut decompressed).unwrap();
// Deserialize
let decoded: Vec<i32> = deserialize(&decompressed[..]).unwrap();
assert_eq!(numbers, decoded);
}
在这个示例中,我们定义了一个包含整数的向量。我们将其序列化为一个字节数组,然后将其压缩为另一个字节数组。我们将压缩后的字节数组解压缩为另一个字节数组,然后将其反序列化回一个整数向量,并将其与原始向量进行比较。
使用自定义配置序列化和反序列化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
use bincode::{serialize_with, deserialize_from, config};
use std::io::{Cursor, Write};
#[derive(Debug, PartialEq)]
struct Person {
name: String,
age: u8,
}
fn main() {
let person = Person {
name: "Alice".to_string(),
age: 25,
};
// Serialize
let mut buffer = Cursor::new(Vec::new());
serialize_with(&mut buffer, &person, config().big_endian()).unwrap();
let encoded = buffer.into_inner();
// Deserialize
let mut cursor = Cursor::new(encoded);
let decoded: Person = deserialize_from(&mut cursor, config().big_endian()).unwrap();
assert_eq!(person, decoded);
}
在这个示例中,我们定义了一个Person
结构体,它有一个name
字段和一个age
字段。我们将其序列化为一个字节数组,并使用自定义配置将其编码为大端字节序。我们将编码后的字节数组反序列化回Person
结构体,并使用相同的自定义配置来解码它。
进阶用法
自定义序列化和反序列化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
use bincode::{serialize, deserialize, Error, ErrorKind};
use std::io::{Cursor, Write, Read};
#[derive(Debug, PartialEq)]
struct Person {
name: String,
age: u8,
}
impl Person {
fn serialize<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
let name_bytes = self.name.as_bytes();
if name_bytes.len() > 255 {
return Err(Error::new(ErrorKind::Custom("name too long".to_string())));
}
writer.write_all(&(name_bytes.len() as u8).to_le_bytes())?;
writer.write_all(name_bytes)?;
writer.write_all(&self.age.to_le_bytes())?;
Ok(())
}
fn deserialize<R: Read>(reader: &mut R) -> Result<Self, Error> {
let mut name_len_bytes = [0; 1];
reader.read_exact(&mut name_len_bytes)?;
let name_len = name_len_bytes[0] as usize;
let mut name_bytes = vec![0; name_len];
reader.read_exact(&mut name_bytes)?;
let name = String::from_utf8(name_bytes)?;
let mut age_bytes = [0; 1];
reader.read_exact(&mut age_bytes)?;
let age = age_bytes[0];
Ok(Person { name, age })
}
}
fn main() {
let person = Person {
name: "Alice".to_string(),
age: 25,
};
// Serialize
let mut buffer = Cursor::new(Vec::new());
person.serialize(&mut buffer).unwrap();
let encoded = buffer.into_inner();
// Deserialize
let mut cursor = Cursor::new(encoded);
let decoded: Person = Person::deserialize(&mut cursor).unwrap();
assert_eq!(person, decoded);
}
在这个示例中,我们定义了一个Person
结构体,并实现了自定义的序列化和反序列化方法。在序列化方法中,我们将名称长度编码为一个字节,然后将名称和年龄编码为字节数组。在反序列化方法中,我们首先读取名称长度字节,然后读取名称和年龄字节,并将它们解码为一个Person
结构体。
自定义大小端序列化和反序列化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
use bincode::{serialize, deserialize, Error, ErrorKind};
use std::io::{Cursor, Write, Read};
#[derive(Debug, PartialEq)]
struct Person {
name: String,
age: u8,
}
impl Person {
fn serialize<W: Write>(&self, writer: &mut W, big_endian: bool) -> Result<(), Error> {
let name_bytes = self.name.as_bytes();
if name_bytes.len() > 255 {
return Err(Error::new(ErrorKind::Custom("name too long".to_string())));
}
let mut name_len_bytes = [0; 1];
name_len_bytes[0] = name_bytes.len() as u8;
if big_endian {
writer.write_all(&name_len_bytes[..].reverse())?;
} else {
writer.write_all(&name_len_bytes[..])?;
}
writer.write_all(name_bytes)?;
writer.write_all(&self.age.to_le_bytes())?;
Ok(())
}
fn deserialize<R: Read>(reader: &mut R, big_endian: bool) -> Result<Self, Error> {
let mut name_len_bytes = [0; 1];
reader.read_exact(&mut name_len_bytes)?;
let name_len = if big_endian {
u8::from_be_bytes(name_len_bytes)
} else {
u8::from_le_bytes(name_len_bytes)
} as usize;
let mut name_bytes = vec![0; name_len];
reader.read_exact(&mut name_bytes)?;
let name = String::from_utf8(name_bytes)?;
let mut age_bytes = [0; 1];
reader.read_exact(&mut age_bytes)?;
let age = age_bytes[0];
Ok(Person { name, age })
}
}
fn main() {
let person = Person {
name: "Alice".to_string(),
age: 25,
};
// Serialize
let mut buffer = Cursor::new(Vec::new());
person.serialize(&mut buffer, true).unwrap();
let encoded = buffer.into_inner();
// Deserialize
let mut cursor = Cursor::new(encoded);
let decoded: Person = Person::deserialize(&mut cursor, true).unwrap();
assert_eq!(person, decoded);
}
在这个示例中,我们定义了一个Person
结构体,并实现了自定义的大小端序列化和反序列化方法。在序列化方法中,我们将名称长度编码为一个字节,并根据big_endian
参数决定字节序。在反序列化方法中,我们首先读取名称长度字节,并根据big_endian
参数解码字节序。然后,我们读取名称和年龄字节,并将它们解码为一个Person
结构体。
序列化和反序列化一个动态数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
use bincode::{serialize, deserialize};
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Person {
name: String,
age: u8,
}
fn main() {
let people = vec![
Person {
name: "Alice".to_string(),
age: 25,
},
Person {
name: "Bob".to_string(),
age: 30,
},
Person {
name: "Charlie".to_string(),
age: 35,
},
];
// Serialize
let encoded: Vec<u8> = serialize(&people).unwrap();
// Deserialize
let decoded: Vec<Person> = deserialize(&encoded[..]).unwrap();
assert_eq!(people, decoded);
}
在这个示例中,我们定义了一个包含Person
结构体的动态数组。我们将其序列化为一个字节数组,然后将其反序列化回一个Person
结构体的动态数组,并将其与原始数组进行比较。
序列化和反序列化一个结构体的子集
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
use bincode::{serialize, deserialize};
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Person {
name: String,
age: u8,
address: String,
}
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct PersonSubset {
name: String,
age: u8,
}
fn main() {
let person = Person {
name: "Alice".to_string(),
age: 25,
address: "123 Main St".to_string(),
};
// Serialize subset
let encoded: Vec<u8> = serialize(&PersonSubset {
name: person.name.clone(),
age: person.age,
})
.unwrap();
// Deserialize subset
let decoded: PersonSubset = deserialize(&encoded[..]).unwrap();
assert_eq!(
decoded,
PersonSubset {
name: "Alice".to_string(),
age: 25
}
);
// Deserialize full struct from subset bytes
let decoded_full: Person = deserialize(&encoded[..]).unwrap();
assert_eq!(
decoded_full,
Person {
name: "Alice".to_string(),
age: 25,
address: "".to_string()
}
);
// Serialize full struct to subset bytes
let encoded_subset: Vec<u8> = serialize(&PersonSubset {
name: person.name.clone(),
age: person.age,
})
.unwrap();
assert_eq!(encoded, encoded_subset);
}
在这个示例中,我们定义了一个Person
结构体,它有一个name
字段、一个age
字段和一个address
字段。我们将其序列化为一个字节数组,然后将其反序列化回一个PersonSubset
结构体的字节数组,该结构体只包含name
和age
字段。我们还演示了如何从子集字节数组反序列化回完整的结构体,以及如何将完整的结构体序列化为子集字节数组。
使用自定义配置
在某些情况下,您可能需要使用自定义配置来序列化和反序列化数据。例如,您可能需要使用大端字节序而不是默认的小端字节序。您可以使用bincode::config()
函数创建一个默认配置,然后使用bincode::serialize_with()
和bincode::deserialize_from()
函数序列化和反序列化数据。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use bincode::{serialize_with, deserialize_from, config};
use std::io::{Cursor, Write};
let person = Person {
name: "Alice".to_string(),
age: 25,
};
// Serialize with big endian byte order
let mut buffer = Cursor::new(Vec::new());
serialize_with(&mut buffer, &person, config().big_endian()).unwrap();
let encoded = buffer.into_inner();
// Deserialize with big endian byte order
let mut cursor = Cursor::new(encoded);
let decoded: Person = deserialize_from(&mut cursor, config().big_endian()).unwrap();
优化序列化和反序列化性能
为了优化序列化和反序列化性能,可以使用bincode::config
模块中的DefaultOptions
和Options
结构体,调整序列化和反序列化的选项。以下是一个优化性能的示例:
1
2
3
4
5
6
7
8
9
10
11
12
use bincode::{serialize_with_options, deserialize_with_options, DefaultOptions};
// 优化性能
let mut options = DefaultOptions::new();
options.limit = bincode::Bounded(1024); // 限制序列化和反序列化的最大字节数
let data = vec![0; 1024 * 1024 * 1024]; // 1GB数据
// 序列化大数据量
let encoded: Vec<u8> = serialize_with_options(&data, options).unwrap();
// 反序列化大数据量
let decoded: Vec<u8> = deserialize_with_options(&encoded[..], options).unwrap();
处理序列化和反序列化错误
在序列化和反序列化过程中,可能会出现错误。为了处理这些错误,可以使用Result
类型和bincode::Error
枚举类型。以下是一个处理错误的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use bincode::{serialize, deserialize, Error};
// 处理错误
let num = "abc";
let encoded: Result<Vec<u8>, Error> = serialize(&num);
match encoded {
Ok(v) => println!("Encoded: {:?}", v),
Err(e) => println!("Error: {:?}", e),
}
let encoded = vec![1, 2, 3];
let decoded: Result<String, Error> = deserialize(&encoded[..]);
match decoded {
Ok(v) => println!("Decoded: {:?}", v),
Err(e) => println!("Error: {:?}", e),
}
总结
Bincode 是 Rust 语言中的一个二进制编码库,可以将 Rust 的数据结构序列化为二进制格式,以便于存储和传输。使用 Bincode 可以方便地将数据序列化为二进制格式,也可以反序列化二进制数据为 Rust 数据结构。Bincode 支持大部分 Rust 的数据类型,包括基本类型、结构体、枚举、数组、元组等。在序列化和反序列化过程中,Bincode 会自动进行类型检查和字节对齐,保证数据的正确性和兼容性。同时,Bincode 还支持自定义序列化和反序列化方法,以满足特殊需求。为了优化序列化和反序列化性能,可以使用bincode::config
模块中的DefaultOptions
和Options
结构体,调整序列化和反序列化的选项。在序列化和反序列化过程中,可能会出现错误,可以使用Result
类型和bincode::Error
枚举类型来处理这些错误。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 TinyZ Zzh (包含链接: https://tinyzzh.github.io ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。 如有任何疑问,请 与我联系 (tinyzzh815@gmail.com) 。
评论