You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 14:36:16