export class BinaryFileParser {
// 解析自定义二进制文件
public static parse(arrayBuffer: ArrayBuffer): any {
let byte = new Laya.Byte(arrayBuffer);
byte.endian = Laya.Byte.LITTLE_ENDIAN;
// 读取文件头
let magic = byte.readUTFBytes(4);
if (magic !== "DATA") {
throw new Error("无效的文件格式");
}
let version = byte.readUint16();
let recordCount = byte.readUint32();
let records = [];
// 读取记录
for (let i = 0; i < recordCount; i++) {
let record = this.readRecord(byte);
records.push(record);
}
return { version, records };
}
private static readRecord(byte: Laya.Byte): any {
let id = byte.readInt32();
let type = byte.readUint8();
let x = byte.readFloat32();
let y = byte.readFloat32();
let name = byte.readUTFString();
return { id, type, x, y, name };
}
// 写入二进制文件
public static write(records: any[]): Laya.Byte {
let byte = new Laya.Byte();
byte.endian = Laya.Byte.LITTLE_ENDIAN;
// 写入文件头
byte.writeUTFBytes("DATA");
byte.writeUint16(1); // 版本
byte.writeUint32(records.length);
// 写入记录
for (let record of records) {
byte.writeInt32(record.id);
byte.writeUint8(record.type);
byte.writeFloat32(record.x);
byte.writeFloat32(record.y);
byte.writeUTFString(record.name);
}
return byte;
}
}
// 使用示例
let data = [
{ id: 1, type: 0, x: 100, y: 200, name: "对象1" },
{ id: 2, type: 1, x: 300, y: 400, name: "对象2" }
];
let fileData = BinaryFileParser.write(data);
let parsed = BinaryFileParser.parse(fileData.buffer);
console.log(parsed);
// 批量写入顶点数据
let byte = new Laya.Byte();
let vertices = [
{ x: 0, y: 0, z: 0 },
{ x: 100, y: 0, z: 0 },
{ x: 0, y: 100, z: 0 },
{ x: 100, y: 100, z: 0 }
];
// 写入顶点数量
byte.writeUint32(vertices.length);
// 写入顶点数据
for (let v of vertices) {
byte.writeFloat32(v.x);
byte.writeFloat32(v.y);
byte.writeFloat32(v.z);
}
// 批量读取
byte.pos = 0;
let count = byte.readUint32();
let loadedVertices = [];
for (let i = 0; i < count; i++) {
loadedVertices.push({
x: byte.readFloat32(),
y: byte.readFloat32(),
z: byte.readFloat32()
});
}
console.log(loadedVertices);
高级技巧
1. 使用常量定义协议字段
typescript复制代码
export class Protocol {
// 消息类型
public static readonly MSG_LOGIN = 1001;
public static readonly MSG_MOVE = 1002;
public static readonly MSG_ATTACK = 1003;
// 数据偏移量
public static readonly OFFSET_MSG_TYPE = 0;
public static readonly OFFSET_MSG_LEN = 2;
public static readonly OFFSET_MSG_DATA = 4;
}
2. 创建 Byte 复用池
typescript复制代码
export class BytePool {
private static pool: Laya.Byte[] = [];
public static get(): Laya.Byte {
if (this.pool.length > 0) {
let byte = this.pool.pop();
byte.clear();
return byte;
}
return new Laya.Byte();
}
public static recover(byte: Laya.Byte): void {
if (this.pool.length < 50) {
this.pool.push(byte);
}
}
}
3. 检查可读数据
typescript复制代码
function safeRead(byte: Laya.Byte): void {
// 检查是否有足够数据可读
if (byte.bytesAvailable < 12) {
console.warn("数据不足");
return;
}
// 安全读取
let a = byte.readInt32();
let b = byte.readFloat32();
let c = byte.readUint32();
}
4. 保存和恢复读取位置
typescript复制代码
function peekData(byte: Laya.Byte): number {
// 保存当前位置
let savedPos = byte.pos;
// 读取数据
let value = byte.readInt32();
// 恢复位置
byte.pos = savedPos;
return value;
}
最佳实践
1. 读写配对原则
typescript复制代码
// ✅ 正确:读写顺序一致
byte.writeInt32(100);
byte.writeFloat32(3.14);
byte.writeUTFString("Hello");
byte.pos = 0;
let a = byte.readInt32();
let b = byte.readFloat32();
let c = byte.readUTFString();
// ❌ 错误:读写顺序不一致会导致数据错乱
2. 网络通信统一字节序
typescript复制代码
// 网络通信建议统一使用大端序
let byte = new Laya.Byte();
byte.endian = Laya.Byte.BIG_ENDIAN; // 网络字节序
3. 使用完毕后清理
typescript复制代码
// 网络消息处理完成后清理
let byte = new Laya.Byte(msg);
// ... 处理数据 ...
byte.clear(); // 释放内存
4. 字符串方法选择
方法
适用场景
特点
writeUTFString / readUTFString
网络协议
带 16 位长度前缀
writeUTFString32 / readUTFString32
大数据传输
带 32 位长度前缀
writeUTFBytes / readUTFBytes
固定长度或已知长度
无长度前缀,需指定长度
5. 错误处理
typescript复制代码
export class SafeByteReader {
public static readInt32Safe(byte: Laya.Byte): number | null {
if (byte.bytesAvailable < 4) {
console.error("数据不足,无法读取 Int32");
return null;
}
return byte.readInt32();
}
public static readStringSafe(byte: Laya.Byte): string | null {
try {
return byte.readUTFString();
} catch (e) {
console.error("读取字符串失败:", e);
return null;
}
}
}