Rust中使用rmp_serde编码含无效UTF-8字符的PathBuf报错求助
解决PathBuf含无效UTF-8字符时rmp_serde序列化报错的问题
问题出在rmp_serde默认会将PathBuf序列化为UTF-8字符串,但Linux下存在含无效UTF-8的路径,直接转字符串会触发错误。要保留字段并完成序列化,核心思路是绕过字符串转换,直接操作PathBuf对应的原始字节序列。
方案一:用serde的with属性指定自定义序列化逻辑
先定义一个处理路径序列化/反序列化的模块,直接将PathBuf转成字节数组存储:
use serde::{Serialize, Deserialize, Serializer, Deserializer}; use std::path::{Path, PathBuf}; use std::ffi::OsStr; mod path_serde { use super::*; // 将PathBuf序列化为字节数组 pub fn serialize<S>(path: &PathBuf, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { // Unix下直接返回路径原始字节,Windows下返回WTF-8编码字节,兼容跨平台 let bytes = path.as_os_str().as_bytes(); serializer.serialize_bytes(bytes) } // 将字节数组反序列化为PathBuf pub fn deserialize<'de, D>(deserializer: D) -> Result<PathBuf, D::Error> where D: Deserializer<'de>, { let bytes = Vec::<u8>::deserialize(deserializer)?; let os_str = OsStr::from_bytes(&bytes); Ok(PathBuf::from(os_str)) } }
然后给结构体的path字段加上#[serde(with = "path_serde")]属性:
use serde::{Serialize, Deserialize}; use std::path::PathBuf; #[derive(Serialize, Deserialize)] struct A { pub first: bool, #[serde(with = "path_serde")] pub path: PathBuf, }
这样序列化时,path会被转成原始字节数组,完全兼容含无效UTF-8的路径;反序列化时再将字节数组转回PathBuf,不丢失任何路径信息。
方案二:手动实现Serialize/Deserialize trait
如果不想用with属性,也可以直接为结构体实现序列化和反序列化逻辑:
use serde::{Serialize, Deserialize, Serializer, Deserializer}; use std::path::PathBuf; use std::ffi::OsStr; #[derive(Debug)] struct A { pub first: bool, pub path: PathBuf, } impl Serialize for A { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { let mut struct_state = serializer.serialize_struct("A", 2)?; struct_state.serialize_field("first", &self.first)?; // 直接序列化路径的原始字节 struct_state.serialize_field("path", self.path.as_os_str().as_bytes())?; struct_state.end() } } impl<'de> Deserialize<'de> for A { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { // 定义辅助结构体临时接收反序列化数据 #[derive(Deserialize)] struct TempA { first: bool, path: Vec<u8>, } let temp = TempA::deserialize(deserializer)?; let path = PathBuf::from(OsStr::from_bytes(&temp.path)); Ok(A { first: temp.first, path }) } }
注意事项
- 序列化后
path字段以字节数组形式存储,若需跨语言解析,需将字节数组转换为对应系统的路径格式(如Unix直接用字节构路径,Windows需将WTF-8字节转回宽字符)。 - 两种方案都能完整保留路径信息,不会因为无效UTF-8丢失数据。
内容的提问来源于stack exchange,提问作者Rusting_It
相关产品推荐
相关产品推荐

