C#实现非JSON游戏存档手动映射转JSON及技术咨询
C#处理非标准游戏存档的实现方案
核心结论
不需要手动用StringBuilder构建JSON,直接构建DTO对象是更高效、更可靠的方案;如果确实需要JSON作为中间格式,也可以直接通过序列化DTO生成,无需手动拼接。
具体实现步骤
1. 定义匹配存档结构的DTO类
直接对应你期望的结构定义C#类,覆盖固定字节段和可修改属性:
public class SaveFileDto { public string HeaderBytes { get; set; } public List<ItemDto> Items { get; set; } public string FooterBytes { get; set; } } public class ItemDto { public string HeaderBytes { get; set; } public PositionDto Position { get; set; } public string BytesBetweenPositionAndRotation { get; set; } public RotationDto Rotation { get; set; } public string FooterBytes { get; set; } } public class PositionDto { public string X { get; set; } public string Y { get; set; } public string Z { get; set; } } public class RotationDto { public string X { get; set; } public string Y { get; set; } public string Z { get; set; } }
2. 从原始字节流直接构建DTO
使用BinaryReader读取存档文件,根据你分析出的字节映射规则,将固定字节段转为十六进制字符串(借助BitConverter.ToString()),拆分可变属性字节段赋值给DTO:
using (var reader = new BinaryReader(File.OpenRead("game_save"))) { var saveDto = new SaveFileDto(); // 读取文件头固定字节并转十六进制字符串 var headerBytes = reader.ReadBytes(/* 替换为实际文件头字节长度 */); saveDto.HeaderBytes = BitConverter.ToString(headerBytes); saveDto.Items = new List<ItemDto>(); while (/* 替换为判断是否还有物品数据的逻辑 */) { var itemDto = new ItemDto(); // 读取物品头固定字节 var itemHeader = reader.ReadBytes(/* 替换为实际物品头长度 */); itemDto.HeaderBytes = BitConverter.ToString(itemHeader); // 验证Position标识字节(80-3F) var posMarker = reader.ReadBytes(2); if (BitConverter.ToString(posMarker) != "80-3F") { // 处理异常或跳过当前物品 continue; } // 读取X/Y/Z各4字节 itemDto.Position = new PositionDto { X = BitConverter.ToString(reader.ReadBytes(4)), Y = BitConverter.ToString(reader.ReadBytes(4)), Z = BitConverter.ToString(reader.ReadBytes(4)) }; // 读取Position与Rotation之间的固定字节 var betweenBytes = reader.ReadBytes(/* 替换为实际中间字节长度 */); itemDto.BytesBetweenPositionAndRotation = BitConverter.ToString(betweenBytes); // 读取Rotation数据(参照Position的逻辑实现) // ... // 读取物品尾固定字节 var itemFooter = reader.ReadBytes(/* 替换为实际物品尾长度 */); itemDto.FooterBytes = BitConverter.ToString(itemFooter); saveDto.Items.Add(itemDto); } // 读取文件尾固定字节 var footerBytes = reader.ReadBytes(/* 替换为实际文件尾长度 */); saveDto.FooterBytes = BitConverter.ToString(footerBytes); }
3. 修改DTO后还原为原始存档
使用BinaryWriter将DTO中的十六进制字符串转回字节数组,按原始结构写入文件:
using (var writer = new BinaryWriter(File.OpenWrite("modified_game_save"))) { // 写入文件头 writer.Write(ConvertHexToBytes(saveDto.HeaderBytes)); foreach (var item in saveDto.Items) { // 写入物品头 writer.Write(ConvertHexToBytes(item.HeaderBytes)); // 写入Position标识字节 writer.Write(new byte[] { 0x80, 0x3F }); // 写入Position的X/Y/Z writer.Write(ConvertHexToBytes(item.Position.X)); writer.Write(ConvertHexToBytes(item.Position.Y)); writer.Write(ConvertHexToBytes(item.Position.Z)); // 写入中间固定字节 writer.Write(ConvertHexToBytes(item.BytesBetweenPositionAndRotation)); // 写入Rotation数据 // ... // 写入物品尾 writer.Write(ConvertHexToBytes(item.FooterBytes)); } // 写入文件尾 writer.Write(ConvertHexToBytes(saveDto.FooterBytes)); } // 辅助方法:十六进制字符串转字节数组(去除连字符) private static byte[] ConvertHexToBytes(string hexString) { hexString = hexString.Replace("-", string.Empty); byte[] bytes = new byte[hexString.Length / 2]; for (int i = 0; i < bytes.Length; i++) { bytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); } return bytes; }
4. 关于JSON中间格式的选择
如果需要JSON作为中间层(比如存档配置、跨系统交互),可以直接用System.Text.Json或Newtonsoft.Json序列化/反序列化DTO,示例:
// DTO转JSON string json = JsonSerializer.Serialize(saveDto, new JsonSerializerOptions { WriteIndented = true }); // JSON转DTO SaveFileDto saveDtoFromJson = JsonSerializer.Deserialize<SaveFileDto>(json);
但直接操作DTO比经过JSON中间步骤更高效,减少了序列化开销,也避免了手动拼接JSON的错误。
内容的提问来源于stack exchange,提问作者Tyler Mason
相关产品推荐
相关产品推荐

