Go语言读写二进制文件(附带实例)
Go 语言的二进制格式是一个自描述的二进制序列。从其内部表示来看,Go 语言的二进制格式由一个 0 块或更多块的序列组成,其中每块都包含一个字节数,一个由 0 个或多个 typeId-typeSpecification 对(即“类型对”)组成的序列,以及一个 typeId-value 对(即“值对”)。
如果 typeId-value 对的 typeId 是预先定义好的(如 bool、int 和 string 等),则这些 typeId-typeSpecification 对可以省略。否则就要用类型对描述一个自定义类型(如一个自定义的结构体)。类型对和值对之间的 typeId 没有区别。
类型对和值对源于 C++ 语言的类型和值。对此感兴趣的读者可自行查阅相关资料。
下面通过几个实例演示如何对 gob 格式的二进制文件执行写入、读取操作。
【实例 1】对 gob 格式的二进制文件执行写入操作。在当前程序所在的目录下,创建名为 output.gob 的二进制 gob 格式文件,把诗句“黄沙百战穿金甲,不破楼兰终不还。”写入 output.gob。代码如下:

图 1 对 gob 格式的二进制文件执行写入操作
【实例 2】对 gob 格式的二进制文件执行读取操作。读取名为 output.gob 的二进制 gob 格式文件,把 output.gob 中的数据打印在控制台上。代码如下:
在开发过程中,以 Go 语言 gob 格式的读写通常比自定义二进制格式快很多,而且创建的文件也不大。但是,当必须使用 gob.GobEncoder 和 gob.GobDecoder 接口处理一些不可被 gob 格式编码的数据时,需要自定义二进制格式。
使用 encoding/binary 包的 binary.Write() 函数以二进制格式写数据非常简单,其语法格式如下:
下面通过几个实例演示如何对自定义格式的二进制文件执行写入、读取操作。
【实例 3】对自定义格式的二进制文件执行写入操作。在当前程序所在的目录下,创建名为 output.bin 的自定义格式二进制文件,把数字 1~10 依次写入 output.bin 中。代码如下:

图 2 对自定义格式的二进制文件执行写入操作
【实例 4】对自定义格式的二进制文件执行读取操作。对自定义格式二进制文件 output.bin 执行读取操作,把 output.bin 中的数据打印在控制台上。代码如下:
如果 typeId-value 对的 typeId 是预先定义好的(如 bool、int 和 string 等),则这些 typeId-typeSpecification 对可以省略。否则就要用类型对描述一个自定义类型(如一个自定义的结构体)。类型对和值对之间的 typeId 没有区别。
类型对和值对源于 C++ 语言的类型和值。对此感兴趣的读者可自行查阅相关资料。
gob格式
Go 语言中的 encoding/gob 包也提供了与 encoding/json 包一样的编码、解码功能。通常而言,如果对文件的可读性没有要求,gob 格式是 Go 语言中文件存储和网络传输最方便的格式。下面通过几个实例演示如何对 gob 格式的二进制文件执行写入、读取操作。
【实例 1】对 gob 格式的二进制文件执行写入操作。在当前程序所在的目录下,创建名为 output.gob 的二进制 gob 格式文件,把诗句“黄沙百战穿金甲,不破楼兰终不还。”写入 output.gob。代码如下:
package main
import (
"encoding/gob"
"fmt"
"os"
)
func main() {
// 待编码的诗句
info := "黄沙百战穿金甲,不破楼兰终不还。"
// 创建输出文件
file, err := os.Create("output.gob")
if err != nil {
fmt.Println("文件创建失败", err.Error())
return
}
defer file.Close()
// 创建 gob 编码器
encoder := gob.NewEncoder(file)
// 编码并写入
err = encoder.Encode(info)
if err != nil {
fmt.Println("编码错误", err.Error())
return
}
// 编码成功
fmt.Println("编码成功")
}
运行程序后,当控制台打印“编码成功”时,说明在当前程序所在的目录下,已经创建 output.gob,如下图所示:
图 1 对 gob 格式的二进制文件执行写入操作
【实例 2】对 gob 格式的二进制文件执行读取操作。读取名为 output.gob 的二进制 gob 格式文件,把 output.gob 中的数据打印在控制台上。代码如下:
package main
import (
"encoding/gob" // 原图左引号错误,已修正
"fmt"
"os"
)
func main() {
// 打开 gob 文件
file, err := os.Open("output.gob")
if err != nil {
fmt.Println("文件打开失败", err.Error())
return
}
defer file.Close()
// 创建 gob 解码器
decoder := gob.NewDecoder(file)
// 定义变量用于接收解码结果
var info string
// 解码
err = decoder.Decode(&info)
if err != nil {
fmt.Println("解码失败", err.Error())
} else {
fmt.Println("解码成功")
fmt.Println(info)
}
}
运行结果如下:
解码成功
黄沙百战穿金甲,不破楼兰终不还。
自定义二进制格式
Go 语言的 encoding/gob 包非常易用,并且使用时所需代码量也非常少,但有时仍需要创建自定义的二进制格式。自定义的二进制格式的数据表示可以更紧凑,并且读写速度非常快。在开发过程中,以 Go 语言 gob 格式的读写通常比自定义二进制格式快很多,而且创建的文件也不大。但是,当必须使用 gob.GobEncoder 和 gob.GobDecoder 接口处理一些不可被 gob 格式编码的数据时,需要自定义二进制格式。
使用 encoding/binary 包的 binary.Write() 函数以二进制格式写数据非常简单,其语法格式如下:
func Write(w io.Writer, order ByteOrder, data interface{}) error
语法说明如下:
- Write() 函数把参数 data 的 binary 编码格式写入参数 w;
- 参数 data 必须是定长值、定长值的切片、定长值的指针;
- 参数 order 指定写入数据的字节序,当写入结构体时,名字中有 _ 的字段会置为 0。
下面通过几个实例演示如何对自定义格式的二进制文件执行写入、读取操作。
【实例 3】对自定义格式的二进制文件执行写入操作。在当前程序所在的目录下,创建名为 output.bin 的自定义格式二进制文件,把数字 1~10 依次写入 output.bin 中。代码如下:
package main
import (
"bytes"
"encoding/binary"
"fmt"
"os"
)
// Website 结构体定义
type Website struct {
Url int32
}
func main() {
// 创建输出文件
file, err := os.Create("output.bin")
if err != nil {
fmt.Println("文件创建失败", err.Error())
return
}
defer file.Close()
// 循环写入 10 条记录
for i := 1; i <= 10; i++ {
info := Website{
Url: int32(i),
}
// 将结构体编码为二进制
var binBuf bytes.Buffer
err := binary.Write(&binBuf, binary.LittleEndian, info)
if err != nil {
fmt.Println("编码失败", err.Error())
return
}
// 写入文件
_, err = file.Write(binBuf.Bytes())
if err != nil {
fmt.Println("写入失败", err.Error())
return
}
}
fmt.Println("编码成功")
}
运行程序后,当控制台打印“编码成功”时,说明在当前程序所在的目录下创建 output.bin,如下图所示。
图 2 对自定义格式的二进制文件执行写入操作
【实例 4】对自定义格式的二进制文件执行读取操作。对自定义格式二进制文件 output.bin 执行读取操作,把 output.bin 中的数据打印在控制台上。代码如下:
package main
import (
"bytes"
"encoding/binary"
"fmt"
"os"
)
// Website 结构体定义
type Website struct {
Url int32
}
func main() {
// 打开二进制文件
file, err := os.Open("output.bin")
if err != nil {
fmt.Println("文件打开失败", err.Error())
return
}
defer file.Close()
m := Website{}
// 循环读取 10 条记录
for i := 1; i <= 10; i++ {
data := readNextBytes(file, 4) // 读取 4 字节
buffer := bytes.NewBuffer(data) // 构造缓冲区
err := binary.Read(buffer, binary.LittleEndian, &m)
if err != nil {
fmt.Println("二进制文件读取失败", err)
return
}
fmt.Println("第", i, "个值为:", m)
}
}
// readNextBytes 从文件中读取指定字节数
func readNextBytes(file *os.File, number int) []byte {
bytes := make([]byte, number)
_, err := file.Read(bytes)
if err != nil {
fmt.Println("解码失败", err)
}
return bytes
}
运行结果如下:
第 1 个值为:{1}
第 2 个值为:{2}
第 3 个值为:{3}
第 4 个值为:{4}
第 5 个值为:{5}
第 6 个值为:{6}
第 7 个值为:{7}
第 8 个值为:{8}
第 9 个值为:{9}
第 10 个值为:{10}
ICP备案:
公安联网备案: