行业资讯 2025年08月6日
0 收藏 0 点赞 416 浏览 3882 个字
摘要 :

文章目录 一、问题复现 (一)相关类定义 (二)执行代码 (三)执行效果与错误日志 二、解决方式 (一)去除前导字符 (二)条件判断后去除 三、问题原因 最近遇……




  • 一、问题复现
    • (一)相关类定义
    • (二)执行代码
    • (三)执行效果与错误日志
  • 二、解决方式
    • (一)去除前导字符
    • (二)条件判断后去除
  • 三、问题原因

最近遇到对象序列化与反序列化过程中出现异常。下面就来详细说说这个“对象转成json后转成byte[]后再转成string,反序列化时提示失败第一个字符是问号”的问题,以及该如何解决。

一、问题复现

在实际开发场景中,我们需要将一个对象先转成json格式,再把json转成byte[] ,通过网络传输后,再将其反序列化为对象。然而,在反序列化这一步却出现了错误。当打印出要反序列化的json字符串时,发现其开头多了一个问号,这就是导致反序列化失败的“罪魁祸首”。

为了让大家更清楚,下面看看具体的代码示例。

(一)相关类定义

  1. TextMessage类
using System.Threading;

namespace SocketTools
{
    public class TextMessage : Message
    {

        private string message;

        public string Message { get => message; set => message = value; }

        public TextMessage()
        {

        }


        public TextMessage(string userName, string targetName, string sendTime, string message) : base(userName, targetName, sendTime, MessageType.Text)
        {
            this.message = message;
        }
    }
}

这个类继承自Message类,用于表示文本消息,包含消息内容等属性。

  1. Message类
using Newtonsoft.Json;

namespace SocketTools
{

    public enum MessageType
    {
        Connection = 0,
        Text,
        Image,
        Mixed,
        Recall,
        File,

    }

    public class Message
    {
        private string userName;
        private string targetName;
        private string sendTime;
        private MessageType messageType;

        public string UserName { get => userName; set => userName = value; }
        public string TargetName { get => targetName; set => targetName = value; }
        public string SendTime { get => sendTime; set => sendTime = value; }
        public MessageType MessageType { get => messageType; set => messageType = value; }

        public Message()
        {

        }

        public Message(string userName, string targetName, string sendTime, MessageType messageType)
        {
            UserName = userName;
            TargetName = targetName;
            SendTime = sendTime;
            MessageType = messageType;
        }

       // 序列化方法
       public static string Serialize(Message message)
       {
           return JsonConvert.SerializeObject(message);
       }

       // 反序列化方法
       public static T Deserialize<T>(string json) where T : Message, new()
       { 
   return JsonConvert.DeserializeObject<T>(json );
  
       }
     

    }

}

Message类是一个基础类,定义了消息的一些通用属性和序列化、反序列化方法,其中MessageType是一个枚举类型,用于表示消息的类型。

(二)执行代码

using SocketTools;
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

namespace FunctionalTesting
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            string msg = \"消息内容Q1_2_end\";
            string userName = \"AAAAAAAAAAAAAAAA\";
            string targetUserName = \"CCCCCCCCCCCCCCCC\";


            TextMessage textMessage = new TextMessage(userName,
                targetUserName,
                DateTime.Now.ToString(\"yy-MM-dd-H:m:s\"),
                msg);

            // 按照指定的格式创建消息字符串
            string message = Message.Serialize(textMessage);
            Console.WriteLine(message);
            // 将消息字符串转换为字节流
            byte[] data;
            using (MemoryStream ms = new MemoryStream())
            {
                using (StreamWriter sw = new StreamWriter(ms, Encoding.UTF8))
                {
                    sw.Write(message);
                    sw.Flush();
                    ms.Position = 0;
                    data = ms.ToArray();
                }
            }
            string data2 = Encoding.UTF8.GetString(data);
            Console.WriteLine(data2);
            data2 = Regex.Replace(data2, @\"^\\s+\", \"\");
            Console.WriteLine(data2);

            var d = Message.Deserialize<TextMessage>(data2);
            Console.WriteLine(d.TargetName);
            Console.WriteLine(d.UserName);
            Console.WriteLine(d.MessageType);
            Console.ReadLine();

        }
    }
}

在这段代码中,我们创建了一个TextMessage对象,将其序列化后转换为字节流,再转换回字符串,最后尝试反序列化。

(三)执行效果与错误日志

执行上述代码后,输出的json字符串开头出现了问号:

?{\"Message\":\"消息内容Q1_2_end\",\"UserName\":\"AAAAAAAAAAAAAAAA\",\"TargetName\":\"CCCCCCCCCCCCCCCC\",\"SendTime\":\"23-12-04-1:14:43\",\"MessageType\":1}

同时,反序列化时抛出错误,错误日志如下:

Newtonsoft.Json.JsonReaderException
  HResult=0x80131500
  Message=Unexpected character encountered while parsing value: . Path \'\', line 0, position 0.

但打印原本未经过转换的对象序列化后的字符串,是没有开头这个问号的。

二、解决方式

针对这个问题,有两种常见的解决办法。

(一)去除前导字符

修改反序列化代码,直接去除字符串开头的前导字符。可以使用TrimStart方法,代码如下:

// 反序列化方法
public static T Deserialize<T>(string json) where T : Message, new()
{ 
    return JsonConvert.DeserializeObject<T>(json.TrimStart(\'\\uFEFF\'));
}

这里的\\uFEFF就是导致问题的特殊字符,通过TrimStart方法将其去除后,反序列化就能正常进行。

(二)条件判断后去除

还可以通过判断字符串的第一个字符来决定是否去除。如果第一个字符不是{ 或者[ ,就去除第一个字符,代码如下:

public static T Deserialize<T>(string json) where T : Message, new()
{ 
    if (json[0] == \'{\' || json[0] == \'[\')
    {
    }
    else
    {
        json = json.Remove(0, 1);
    }
    return JsonConvert.DeserializeObject<T>(json);
}

这种方式更加灵活,能适应更多复杂的情况。

三、问题原因

出现这个问题的根源在于零宽度不中断空格(Unicode U+FEFF)字符,也就是常说的BOM(Byte Order Mark)。在使用Unicode编码的文本文件或数据流中,BOM字符用来表示字节顺序。比如在UTF – 16编码里,一个字符由两个字节组成,不同系统和平台下这两个字节的顺序可能不同,BOM字符就能帮助解析器确定字节顺序,正确解码文件中的其他字符。

但在网络通信、数据库存储等数据交换场景中,BOM字符可能会被意外包含在字符串里,这就会导致解析错误。所以在处理这类字符串前,检查并移除不需要的BOM字符是很有必要的。

通过以上对问题的复现、解决方式的介绍以及原因剖析,希望大家在遇到类似问题时,能够快速定位并解决。

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/10493.html

管理员

相关推荐
2025-08-06

文章目录 一、Reader 接口概述 1.1 什么是 Reader 接口? 1.2 Reader 与 InputStream 的区别 1.3 …

988
2025-08-06

文章目录 一、事件溯源 (一)核心概念 (二)Kafka与Golang的优势 (三)完整代码实现 二、命令…

465
2025-08-06

文章目录 一、证明GC期间执行native函数的线程仍在运行 二、native线程操作Java对象的影响及处理方…

348
2025-08-06

文章目录 一、事务基础概念 二、MyBatis事务管理机制 (一)JDBC原生事务管理(JdbcTransaction)…

456
2025-08-06

文章目录 一、SnowFlake算法核心原理 二、SnowFlake算法工作流程详解 三、SnowFlake算法的Java代码…

517
2025-08-06

文章目录 一、本地Jar包的加载操作 二、本地Class的加载方法 三、远程Jar包的加载方式 你知道Groo…

832
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号