
本文介绍了如何使用 Go 语言处理从标准输入读取的 JSON 数据流,该数据流中 JSON 结构体之间穿插着非 JSON 字符串(例如 “end”)。我们将探讨如何读取数据流,过滤掉非 JSON 内容,并将有效的 JSON 数据反序列化为 Go 结构体。
处理混合 JSON 和非 JSON 内容的数据流
在某些情况下,我们可能需要处理包含 JSON 数据和其他类型数据的混合数据流。例如,一个应用程序可能通过标准输入发送 JSON 结构体,并在每个结构体之后添加一个 “end” 字符串作为分隔符。Go 的 encoding/json 包默认情况下无法直接处理这种数据流,因为它期望输入是纯粹的 JSON 格式。
以下是一种处理这种情况的方法,它放弃了 json.Decoder,转而使用 io.Reader 和 json.Unmarshal:
示例代码
package mainimport ( "bytes" "encoding/json" "fmt" "os")// MyStruct 定义了要反序列化的 JSON 结构type MyStruct struct { Command string `json:"command"` ID string `json:"id"` Msg string `json:"msg,omitempty"` //omitempty 表示如果 Msg 字段为空,则在 JSON 中省略}func main() { // 创建一个缓冲区来保存流数据 data := make([]byte, 5000) // 从 stdin 循环读取数据 for { n, err := os.Stdin.Read(data) if err != nil { fmt.Println("Error reading from stdin:", err) return // 或者根据需要进行错误处理 } // 查找换行符的索引,用于分隔 JSON 结构 index := bytes.Index(data[:n], []byte("n")) // 如果没有找到换行符,则继续读取更多数据 if index == -1 { fmt.Println("No newline found, reading more data") continue } // 提取 JSON 数据部分 jsonData := data[:index] // 创建 MyStruct 实例 var myStruct MyStruct // 将 JSON 数据反序列化到 MyStruct err = json.Unmarshal(jsonData, &myStruct) if err != nil { fmt.Println("Error unmarshalling JSON:", err) continue // 或者根据需要进行错误处理 } // 对 myStruct 进行操作 fmt.Printf("Received: %+vn", myStruct) // 移除已处理的数据和 "endn" 字符串 remainingData := data[index+len("nendn"):] copy(data, remainingData) // 重置 buffer 的剩余部分 for i := len(remainingData); i < len(data); i++ { data[i] = 0 } }}
代码解释:
定义结构体: MyStruct 定义了要从 JSON 数据反序列化到的 Go 结构体。 json:”command” 等标记用于指定 JSON 字段与结构体字段之间的映射关系。读取数据: 使用 os.Stdin.Read(data) 从标准输入读取数据到缓冲区 data 中。查找分隔符: bytes.Index(data[:n], []byte(“n”)) 查找换行符的索引,用于分隔 JSON 结构体和 end 字符串。 data[:n] 确保只在实际读取到的数据范围内查找。提取 JSON 数据: jsonData := data[:index] 提取 JSON 数据部分。反序列化 JSON: json.Unmarshal(jsonData, &myStruct) 将 JSON 数据反序列化到 MyStruct 结构体中。错误处理: 代码包含错误处理逻辑,用于处理读取和反序列化过程中可能出现的错误。移除已处理的数据: remainingData := data[index+len(“nendn”):] 获取剩余未处理的数据,并将数据复制到 data 缓冲区的起始位置。 copy(data, remainingData) 确保数据不会丢失。重置缓冲区: 将缓冲区中剩余部分重置为 0,避免旧数据干扰下一次读取。
编译并运行代码
将代码保存为 main.go,然后在终端中运行以下命令:
go run main.go
现在,你可以向标准输入发送包含 JSON 数据和 “end” 字符串的混合数据流。例如:
echo '{"command": "ack", "id": "1231231"}' | cat - && echo 'end' | cat - && echo '{"command": "fail", "id": "1231231"}' | cat - && echo 'end' | cat -
或者,你可以将数据存储在文件中,然后使用以下命令将文件内容重定向到程序的标准输入:
cat input.txt | go run main.go
其中 input.txt 包含以下内容:
{"command": "ack", "id": "1231231"}end{"command": "fail", "id": "1231231"}end{ "command": "log", "msg": "hello world!"}end
程序将解析 JSON 数据并将其打印到控制台。
注意事项
缓冲区大小: data := make([]byte, 5000) 定义了缓冲区的大小。你需要根据实际情况调整缓冲区的大小,以确保能够容纳完整的 JSON 结构体和分隔符。错误处理: 示例代码包含基本的错误处理,但在实际应用中,你可能需要更完善的错误处理机制,例如记录错误日志或采取其他补救措施。性能: 对于非常大的数据流,这种方法可能不是最有效的。在这种情况下,可以考虑使用流式 JSON 解析器,例如 github.com/json-iterator/go,它可以更有效地处理大型 JSON 数据。分隔符的灵活性: 代码假设分隔符始终是 “endn”。如果分隔符可能发生变化,你需要修改代码以适应不同的分隔符。多余的 end 字符: 如果JSON数据中存在 end 字符,可能会导致解析错误。
总结
本文介绍了一种使用 Go 语言处理包含非 JSON 内容的 JSON 数据流的方法。通过使用 io.Reader 和 json.Unmarshal,我们可以灵活地读取数据流,过滤掉非 JSON 内容,并将有效的 JSON 数据反序列化为 Go 结构体。在实际应用中,你需要根据具体情况调整代码,例如缓冲区大小、错误处理和性能优化。
以上就是使用 Go 处理包含非 JSON 内容的 JSON 流的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1414542.html
微信扫一扫
支付宝扫一扫