Go encoding/hex Encoder 怎样把二进制流连续写成十六进制文本
如果二进制数据不是一次性放在内存里,而是分几次从网络、文件或协议帧写出,encoding/hex.NewEncoder 更合适:它返回一个 io.Writer,每次收到源字节就转成小写十六进制字符并写给下游 Writer。这样可以把“读取分片”和“生成文本”连接起来,不需要先拼成一个大切片。
官方文档:https://pkg.go.dev/encoding/hex@go1.27.3#NewEncoder
hex.NewEncoder(dst)的职责是编码并转写,返回值按io.Writer使用。- 连续调用
Write会连续产生十六进制文本;每个源字节对应两个小写字符。 Write返回的n是已消费的源字节数,错误来自下游 Writer,要立即处理。
先把 Encoder 放在正确的边界上
NewEncoder 接收一个目标 io.Writer,例如 bytes.Buffer、文件或网络响应。它返回的仍然是 Writer,因此调用方只需要持续写入原始字节;编码器内部会把数据转成小写十六进制字符。这个 API 适合持续输出,不适合拿来反向解码,也不负责校验文件内容。
实现上,标准库会把输入分块编码后写给下游;官方源码中的内部缓冲区大小为 1024 个十六进制字符,调用方不应把这个实现细节当成接口承诺。真正需要关注的是:下游写失败后,后续写入会沿用这个错误,不能继续假装输出完整。

用一个小工具连续写入多个分片
下面的小程序把两个分片写进同一个编码器,再从缓冲区取回结果。第二次写入不会覆盖第一次结果,而是从上次结束的位置继续追加,因此输出可以对应连续的协议片段或日志块。
package main
import (
"bytes"
"fmt"
"encoding/hex"
)
func encodeChunks(chunks ...[]byte) (string, error) {
var dst bytes.Buffer
encoder := hex.NewEncoder(&dst)
for _, chunk := range chunks {
// 每个分片都写入同一个 Encoder,编码结果会自然连续。
if _, err := encoder.Write(chunk); err != nil {
// 下游 Writer 出错时立即返回,避免把不完整文本当成成功结果。
return "", err
}
}
return dst.String(), nil
}
func main() {
// 分片可以来自不同读取动作,这里只用两个字节切片演示边界。
text, err := encodeChunks([]byte{0x48, 0x69}, []byte{0x21})
if err != nil {
// 示例程序把错误直接打印出来;服务代码应按业务记录或返回。
panic(err)
}
fmt.Println(text) // 输出 486921
}
这里的 bytes.Buffer 只是内存中的下游 Writer;换成打开的文件或实现了 io.Writer 的网络对象,调用方式不变。由于编码结果长度是源数据的两倍,示例中的三个源字节最终得到六个十六进制字符。
分片写入时要看懂 n 和 err
很多代码只检查 err,却忽略了 n 的含义。对于 hex.NewEncoder 返回的 Writer,n 表示已经从本次输入切片中消费的源字节数量,不是已经写出的十六进制字符数量。若下游 Writer 只写出一部分并返回错误,编码器会把下游错误保留下来,调用方应停止继续发送。
func writeChunks(dst io.Writer, chunks [][]byte) error {
encoder := hex.NewEncoder(dst)
for _, chunk := range chunks {
// n 按源字节计算;不要用 n 直接当作十六进制字符串长度。
n, err := encoder.Write(chunk)
if err != nil {
// 记录当前分片和底层错误,调用方才能决定重试或终止。
return fmt.Errorf("写入十六进制分片失败,已消费 %d 个源字节: %w", n, err)
}
if n != len(chunk) {
// 正常的完整 Writer 应消费整个分片,短写无错误也不能静默忽略。
return fmt.Errorf("十六进制分片短写:%d/%d", n, len(chunk))
}
}
return nil
}
这个函数需要补充 fmt、io 和 encoding/hex 的导入。示例刻意把错误上下文放在调用处,方便把失败定位到具体分片;不要把一次失败后的编码器当成可恢复的全新 Writer 使用。

什么时候改用一次性编码 API
如果数据已经完整存在于一个切片中,hex.EncodeToString 更直接;如果要把结果追加到已有切片,可以使用 hex.AppendEncode。只有当输入会分段到达,或目标本身就是一个持续写入的 Writer 时,NewEncoder 才能体现它的边界优势。
| 场景 | 更合适的选择 | 原因 |
|---|---|---|
| 一次性字节切片 | hex.EncodeToString | 表达简单,直接得到字符串 |
| 追加到已有切片 | hex.AppendEncode | 由调用方管理目标切片 |
| 多个分片持续写出 | hex.NewEncoder | 保持 Writer 链,不必先合并输入 |
| 需要 hexdump 格式 | hex.Dumper | 输出带偏移和可打印区域的转储格式 |
常见问题
NewEncoder 输出大写十六进制吗?
不会。标准库文档说明它写出小写十六进制字符;如果协议要求大写,需要在边界处另行转换或选择能满足协议格式的编码方案。
每个分片之间会自动加空格或换行吗?
不会。多个 Write 的结果会直接连接。分隔符属于协议或日志格式的一部分,应由调用方明确写入,不能期待编码器自动插入。
写入失败后可以继续调用 Write 吗?
不建议。编码器会记住下游错误,后续写入不会恢复一个已经失败的输出链;应保留原始错误并结束这次编码任务。
Go bytes.FieldsFuncSeq 怎样按函数规则惰性遍历字段
- 上一篇
- Go bytes.FieldsFuncSeq 怎样按函数规则惰性遍历字段
- 下一篇
- Go http.Request.Write 怎样把请求写成 HTTP 报文
-
- Golang · Go教程 | 46分钟前 |
- Go unicode/utf8 怎样统计 rune 数而不是字节数
- 262浏览 收藏
-
- Golang · Go教程 | 46分钟前 |
- Go regexp 怎样用 LiteralPrefix 判断固定前缀
- 367浏览 收藏
-
- Golang · Go教程 | 50分钟前 | 标准库 · go · Go 通配符 filepath.Match path.Match 资源名
- Go path 怎样用 Match 判断资源名通配符
- 300浏览 收藏
-
- Golang · Go教程 | 53分钟前 | 标准库 · 正则表达式 · Go教程 · 正则表达式 Go regexp encoding.TextAppender Regexp.AppendText
- Go regexp.Regexp AppendText 怎样保留正则表达式文本
- 454浏览 收藏
-
- Golang · Go教程 | 58分钟前 |
- Go os 怎样用 File.Chmod 维护文件权限位
- 195浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go reflect 怎样区分无效 Value 与零值 Value
- 311浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go text/template 怎样在模板中注册带错误返回值的函数
- 490浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go http.Request.Write 怎样把请求写成 HTTP 报文
- 442浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go bytes.FieldsFuncSeq 怎样按函数规则惰性遍历字段
- 350浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go strconv.AppendQuoteToASCII 怎样让日志只含 ASCII 字符
- 360浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go archive/tar Writer.Flush 怎样在写下一个条目前完成当前条目
- 146浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 647次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 675次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 721次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 680次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 514次使用
-
- Java 性能优化上线清单:从定位、改造到灰度发布
- 2026-06-11 860浏览
-
- Spring Boot 压测验证:Gatling、JMeter 与性能回归门禁
- 2026-06-11 843浏览
-
- Java NMT 非堆内存排查:Direct Buffer、线程栈与 Metaspace 分析
- 2026-06-11 826浏览
-
- Spring Boot 容器内存优化:JVM 堆、非堆与 MaxRAMPercentage
- 2026-06-11 809浏览
-
- Tomcat 连接与线程参数调优:maxThreads、acceptCount 与 KeepAlive
- 2026-06-11 792浏览

