没想到,处理二进制文件这么简单!

本文涉及的产品
云解析DNS-重点域名监控,免费拨测 20万次(价值200元)
日志服务 SLS,月写入数据量 50GB 1个月
简介: 没想到,处理二进制文件这么简单!

1. 概述

1.1 为什么学习二进制文件读写

Go 语言内置了丰富的文件操作函数,可以很方便地处理文本文件。但对于音视频、图像等二进制文件,文本文件函数就不太适用了。

学习 Go 语言的二进制文件读写操作,可以更高效地处理这些非文本文件,在实际项目中也很常用。

1.2 Go 语言处理二进制文件的优势

Go 语言处理二进制文件具有以下优势

性能高,读写速度快

支持跨平台,代码可以在多个系统上运行

内置丰富的编码解码功能,比如 JSON、XML、Protocol Buffers 等

语法简洁,代码可读性好,易于编写和维护


 

2. 文件操作基础

文件操作的一些基础知识。

2.1 创建和打开文件

使用 os.Create() 可以创建一个新文件并打开,使用 os.Open() 可以打开一个已存在的文件


file, err := os.Create("data.bin") // 创建文件
file, err := os.Open("data.bin") // 打开文件

2.2 关闭文件

打开的文件使用后需要关闭


file.Close()

2.3 错误处理

文件操作可能会遇到一些错误,需做错误处理


if err != nil {    // 错误处理}


 

3. 二进制文件读取

下面将详细介绍 Go 语言如何读取二进制文件的不同数据类型。

3.1 读取整数

可使用 binary 包按照不同字节顺序读写整数。

3.1.1 读取固定大小的整数

读取一个 int32 类型的整数


var data int32
err := binary.Read(file, binary.LittleEndian, &data)

3.1.2 读取可变大小的整数

使用 encoding/binary 包的 ReadUvarintReadVarint 函数可以读取可变长度编码的整数。


udata, err := binary.ReadUvarint(file)
data, err := binary.ReadVarint(file)

3.2 读取字符串

字符串可以用 ReadString 直接读取指定长度的字符串:


str, err := binary.ReadString(file, length)

要读取不定长字符串,可以先像上面那样读取一个整形长度,然后再读取指定长度的数据到字符串中。

3.3 读取自定义结构体

可以直接读取到一个结构体变量中


var user StructUserInfo err := binary.Read(file, binary.BigEndian, &user)


 

4. 二进制文件写入

4

data := int32(100)err := binary.Write(file, binary.LittleEndian, data)

4.2 写入可变大小的整数

使用 PutUvarintPutVarint 写入可变长度编码的整数:


err := binary.PutUvarint(file, uint64(x))err := binary.PutVarint(file, x)

4.3 写入字符串

使用 WriteString 写入字符串:


data := "Hello World"err := binary.WriteString(file, data)

4.

user := StructUserInfo{...}err := binary.Write(file, binary.LittleEndian, user)


 

5. 文件指针的移动

可以通过获取和设置文件指针的位置来随机访问文件内容。

5.1 指针位置的获取

Seek 方法获取当前文件的偏移量


n, err := file.Seek(0, io.SeekCurrent) // 获取偏移量

5.2 指针位置的设置

Seek 将指针移动到文件开头或结尾等位置


_, err := file.Seek(0, io.SeekStart) // 移动到开头_, err := file.Seek(0, io.SeekEnd) // 移动到结尾


 

6. 二进制文件的批量处理

6.1 批量读取

在处理大量数据时,可通过缓冲区批量读取数据,提高效率。下面是一个批量读取的例子。


package main
import (  "fmt"  "os")
func main() {  file, err := os.Open("example.bin")  if err != nil {    fmt.Println("Error opening file:", err)    return  }  defer file.Close()
  // 设置缓冲区大小为1024字节  buffer := make([]byte, 1024)
  // 循环读取数据直到文件末尾  for {    n, err := file.Read(buffer)    if err != nil {      fmt.Println("Error reading data:", err)      break    }    if n == 0 {      break    }
    // 处理读取到的数据    fmt.Printf("Read %d bytes: %s\n", n, buffer[:n])  }}

6.2 批量写入

同样地,也可通过缓冲区批量写入数据。下面是批量写入的例子。


package main
import (  "fmt"  "os")
func main() {  file, err := os.Create("example.bin")  if err != nil {    fmt.Println("Error creating file:", err)    return  }  defer file.Close()
  // 设置缓冲区大小为1024字节  buffer := make([]byte, 1024)
  // 循环写入数据  for i := 0; i < 10; i++ {    // 将数据写入缓冲区    data := []byte(fmt.Sprintf("Data %d\n", i))    copy(buffer, data)
    // 写入缓冲区数据到文件    _, err := file.Write(buffer)    if err != nil {      fmt.Println("Error writing data:", err)      return    }  }
  fmt.Println("Batch writing completed.")}


 

7. 实战案例:日志文件的解析与生成

下面以一个日志文件为例,演示二进制文件读写的实际运用。

7.1 日志文件结构分析

假设日志文件的结构如下


type LogHeader struct {    Magic   uint16 // 魔数     Version uint16 // 版本号    Length  uint32 // 日志长度}
type LogItem struct {    Time    int64  // 时间       Message string // 日志消息}

7.2 解析日志文件

解析该日志文件代码如下


func ReadLog(path string) ([]LogItem, error) {
    file, err := os.Open(path)    if err != nil {        return nil, err    }    defer file.Close()
    var header LogHeader    if err := binary.Read(file, binary.BigEndian, &header); err != nil {        return nil, err    }
    var logs []LogItem    for i := 0; i < int(header.Length); i++ {        var log LogItem        if err := binary.Read(file, binary.BigEndian, &log); err != nil {            return nil, err         }        logs = append(logs, log)    }
    return logs, nil}

7.

func WriteLog(path string, logs []LogItem) error {        file, err := os.Create(path)    if err != nil {        return err    }    defer file.Close()
    header := LogHeader{        Magic:   0xDEADBEEF,        Version: 1,        Length:  uint32(len(logs)),    }
    if err := binary.Write(file, binary.BigEndian, header); err != nil {        return err    }
    for _, log := range logs {        if err := binary.Write(file, binary.BigEndian, log); err != nil {            return err        }    }        return nil}


 

8. 性能优化技巧

8.1 缓冲区的使用

通过缓冲区读写可以减少 IO 操作次数,优化性能。使用 bufio 包实现缓冲读写。

8.2 并发读写操作

可通过 goroutine 实现文件读写的并发操作,提高性能。需要正确同步访问文件指针位置。


 

9. 安全性考虑

9.1 数据校验

写入文件时,可以增加 CRC32、MD5 等数据校验,读取时验证数据完整性。

9.2 异常处理

注意添加错误处理逻辑,防止程序异常退出。


 

总结

通过上面介绍,了解了 Go 语言二进制文件的各种读写操作,包括整数、字符串、结构体的编码与解码,指针操作,批量读写与性能优化等技巧,并用日志文件解析和生成的例子做了实战演练。

Go 语言处理二进制文件的功能非常强大,可以开发出高性能和安全的文件处理程序。

目录
相关文章
|
存储 Kubernetes 监控
基于Kubernetes的电商平台部署:实现高可用、弹性伸缩与容器化管理
基于Kubernetes的电商平台部署:实现高可用、弹性伸缩与容器化管理
|
5月前
|
人工智能 测试技术 Go
Go 语言的主流框架
本文全面解析了 Go 语言主流技术生态,涵盖 Web 框架、微服务、数据库工具、测试与部署等多个领域。重点介绍了 Gin、Echo、Beego 等高性能框架,以及 gRPC-Go、Go-Micro 等微服务组件。同时分析了 GORM、Ent 等 ORM 工具与测试部署方案,并结合场景提供选型建议,助力开发者构建高效稳定的 Go 应用。
1272 0
|
JSON API Go
etcd的安装和使用
etcd的安装和使用
407 0
|
人工智能 弹性计算 编解码
阿里云GPU云服务器性能、应用场景及收费标准和活动价格参考
GPU云服务器作为阿里云提供的一种高性能计算服务,通过结合GPU与CPU的计算能力,为用户在人工智能、高性能计算等领域提供了强大的支持。其具备覆盖范围广、超强计算能力、网络性能出色等优势,且计费方式灵活多样,能够满足不同用户的需求。目前用户购买阿里云gpu云服务器gn5 规格族(P100-16G)、gn6i 规格族(T4-16G)、gn6v 规格族(V100-16G)有优惠,本文为大家详细介绍阿里云gpu云服务器的相关性能及收费标准与最新活动价格情况,以供参考和选择。
|
Go API 开发者
深入探讨:使用Go语言构建高性能RESTful API服务
在本文中,我们将探索Go语言在构建高效、可靠的RESTful API服务中的独特优势。通过实际案例分析,我们将展示Go如何通过其并发模型、简洁的语法和内置的http包,成为现代后端服务开发的有力工具。
|
12月前
|
运维 监控 Ubuntu
【运维】如何在Ubuntu中设置一个内存守护进程来确保内存不会溢出
通过设置内存守护进程,可以有效监控和管理系统内存使用情况,防止内存溢出带来的系统崩溃和服务中断。本文介绍了如何在Ubuntu中编写和配置内存守护脚本,并将其设置为systemd服务。通过这种方式,可以在内存使用超过设定阈值时自动采取措施,确保系统稳定运行。
431 4
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的博物馆展览与服务一体化平台附带文章和源代码部署视频讲解等
基于ssm+vue.js+uniapp小程序的博物馆展览与服务一体化平台附带文章和源代码部署视频讲解等
233 0
|
数据可视化 数据挖掘 Python
数据可视化不再难!Matplotlib带你轻松绘制精美图表,让数据分析焕发光彩!
【8月更文挑战第22天】今天分享如何用Python的Matplotlib库绘制多样图表。Matplotlib是数据可视化的强大工具,对数据分析至关重要。本文分六部分:首先介绍环境准备,包括安装和配置;随后通过四个案例演示折线图、柱状图、饼图及散点图的绘制方法;最后总结并鼓励大家进一步探索Matplotlib的丰富功能。跟着示例操作,你将学会基本图表的制作,提升数据展示技能。
250 0
|
存储 NoSQL 关系型数据库
EAV模型(实体-属性-值)的设计和低代码的处理方案(1)
EAV模型(实体-属性-值)的设计和低代码的处理方案(1)
|
Linux Shell 调度
linux服务器定时执行python程序
linux服务器定时执行python程序
1859 0