Dart中如何将对象转换为字节数组?Flutter TCP自定义数据包序列化问题
Flutter 自定义TCP数据包序列化方案
以下是几种适配自定义格式的序列化方案,可直接将对象转成TCP传输用的字节数组:
1. 手动序列化(最灵活,适配自定义格式)
适合需要精确控制字节布局(比如字段顺序、大小端、字节长度)的场景,无额外依赖,性能最优。
示例代码:
import 'dart:typed_data'; import 'dart:convert'; class CustomPacket { final int id; // 4字节整数 final String content; // 先存2字节长度,再存UTF-8内容 final bool isSuccess; // 1字节布尔值(1为true,0为false) CustomPacket({required this.id, required this.content, required this.isSuccess}); // 转成字节数组 Uint8List toBytes() { final contentBytes = utf8.encode(content); final totalBytes = 4 + 2 + contentBytes.length + 1; final byteData = ByteData(totalBytes); // 写入ID(大端模式,可根据协议调整为Endian.little) byteData.setUint32(0, id, Endian.big); // 写入内容长度 byteData.setUint16(4, contentBytes.length, Endian.big); // 写入内容字节 for (int i = 0; i < contentBytes.length; i++) { byteData.setUint8(6 + i, contentBytes[i]); } // 写入布尔值 byteData.setUint8(6 + contentBytes.length, isSuccess ? 1 : 0); return byteData.buffer.asUint8List(); } // 可选:从字节数组解析回对象(接收端用) static CustomPacket fromBytes(Uint8List bytes) { final byteData = ByteData.view(bytes.buffer); final id = byteData.getUint32(0, Endian.big); final contentLength = byteData.getUint16(4, Endian.big); final contentBytes = bytes.sublist(6, 6 + contentLength); final content = utf8.decode(contentBytes); final isSuccess = byteData.getUint8(6 + contentLength) == 1; return CustomPacket(id: id, content: content, isSuccess: isSuccess); } }
2. JSON转字节(开发高效,适合简单格式)
如果自定义格式允许JSON作为数据载体,可快速实现序列化,缺点是有额外字节开销。
示例代码:
import 'dart:typed_data'; import 'dart:convert'; class CustomPacket { final int id; final String content; final bool isSuccess; CustomPacket({required this.id, required this.content, required this.isSuccess}); Uint8List toBytes() { // 转JSON字符串 final jsonStr = jsonEncode({ 'id': id, 'content': content, 'isSuccess': isSuccess, }); final jsonBytes = utf8.encode(jsonStr); // 先写入4字节的JSON长度(方便接收端判断数据包边界) final byteData = ByteData(4 + jsonBytes.length); byteData.setUint32(0, jsonBytes.length, Endian.big); for (int i = 0; i < jsonBytes.length; i++) { byteData.setUint8(4 + i, jsonBytes[i]); } return byteData.buffer.asUint8List(); } static CustomPacket fromBytes(Uint8List bytes) { final byteData = ByteData.view(bytes.buffer); final length = byteData.getUint32(0, Endian.big); final jsonBytes = bytes.sublist(4, 4 + length); final jsonMap = jsonDecode(utf8.decode(jsonBytes)) as Map<String, dynamic>; return CustomPacket( id: jsonMap['id'] as int, content: jsonMap['content'] as String, isSuccess: jsonMap['isSuccess'] as bool, ); } }
3. Protobuf序列化(跨平台友好,适合复杂协议)
如果需要和其他平台(如Java、C++)交互,Protobuf是成熟方案,自动生成的代码能保证字节格式一致。
步骤:
- 定义
.proto文件(比如custom_packet.proto):
syntax = "proto3"; message CustomPacket { int32 id = 1; string content = 2; bool is_success = 3; }
- 安装protobuf工具链,生成Dart代码:
protoc --dart_out=. custom_packet.proto
- 在Flutter中使用生成的代码:
// 序列化 final packet = CustomPacket() ..id = 123 ..content = "Hello TCP" ..isSuccess = true; final bytes = packet.writeToBuffer(); // 反序列化 final receivedPacket = CustomPacket.fromBuffer(bytes);
方案选择建议:
- 私有自定义协议优先选手动序列化,完全可控;
- 快速开发选JSON转字节;
- 跨平台交互选Protobuf。
内容的提问来源于stack exchange,提问作者AhanR
相关产品推荐
相关产品推荐

