设计思路
- 数据读取:使用
bytes.Reader
从数据流中读取数据。由于数据格式多样,需要定义某种标识来区分不同格式的数据块。
- 数据解析:根据标识,对不同格式的数据块进行相应解析。例如,对于JSON数据,使用
json.Unmarshal
解析;对于二进制数据,按照特定的二进制协议解析。
- 数据重组:使用
bytes.Buffer
(实现了 io.Writer
接口)来存储重组后的数据。根据业务需求,将解析后的数据按照新的规则写入 bytes.Buffer
。
- 格式切换处理:通过在数据流中预设特定标识或头部信息来标记数据格式的转换点。在读取数据时,检查这些标识,然后调用相应的解析函数。
- 边界情况处理:处理数据流结束、数据格式标识错误、解析失败等情况。在读取数据时,确保不会越界读取;在解析数据时,对错误进行适当处理。
关键代码示例
package main
import (
"bytes"
"encoding/json"
"fmt"
)
// 假设数据流中用这个标识区分JSON和二进制数据
const jsonMarker = byte(0x01)
// 模拟二进制数据结构
type BinaryData struct {
Value int
}
// 解析JSON数据
func parseJSON(reader *bytes.Reader) (interface{}, error) {
var data interface{}
err := json.NewDecoder(reader).Decode(&data)
return data, err
}
// 解析二进制数据
func parseBinary(reader *bytes.Reader) (interface{}, error) {
var binary BinaryData
err := binary.Read(reader)
return binary, err
}
// 读取数据并解析
func readAndParse(reader *bytes.Reader) (interface{}, error) {
marker := make([]byte, 1)
_, err := reader.Read(marker)
if err != nil {
return nil, err
}
switch marker[0] {
case jsonMarker:
return parseJSON(reader)
default:
return parseBinary(reader)
}
}
// 模拟BinaryData实现io.ReaderFrom接口
func (b *BinaryData) Read(reader *bytes.Reader) error {
return fmt.Errorf("not implemented")
}
func main() {
// 模拟数据流
jsonData := []byte{jsonMarker, '"', 'h', 'e', 'l', 'l', 'o', '"'}
binaryData := []byte{0x02, 0x00, 0x00, 0x00, 0x01}
dataStream := append(jsonData, binaryData...)
reader := bytes.NewReader(dataStream)
result, err := readAndParse(reader)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Parsed JSON:", result)
result, err = readAndParse(reader)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Parsed Binary:", result)
}
边界情况处理
- 数据流结束:在
readAndParse
函数中,当 reader.Read
返回 io.EOF
错误时,说明数据流结束。可以在调用处检查这个错误并做相应处理。
- 数据格式标识错误:在
readAndParse
函数中,当遇到不认识的标识时,返回错误,告知调用者数据格式有误。
- 解析失败:在
parseJSON
和 parseBinary
函数中,如果解析失败,返回相应的错误。调用者可以根据错误类型决定如何处理,例如记录日志、返回特定错误码等。