Skip to content

Go语言笔记

第三方包推荐

命令行

go env

查看全局环境变量和配置

bash
go env

go mod

使用go mod来管理项目,使用以下命令来初始化项目

bash
go mod init project-name

如果缺少依赖可以执行以下命令

bash
go mod tidy

go run

运行main.go

bash
go run main.go

go build

构建当前系统对应的可执行文件(go env里的配置项)

bash
go build

也可以指定系统和架构,以下是常见的系统(GOOS)和 架构(GOARCH):

系统(GOOS):

  • linux(linux系统)
  • windows(windows系统)
  • darwin(mac系统)
  • android(android系统)

架构(GOARCH):

  • amd64(64 位 x86 架构,如 Intel/AMD 64 位 CPU)
  • 386(32 位 x86 架构)
  • arm(ARM 架构,如树莓派、嵌入式设备)
  • arm64(64 位 ARM 架构)

常见组合:

场景GOOSGOARCH
Windows 64 位windowsamd64
Linux 32 位linux386
macOS(Intel)darwinamd64
macOS(Apple Silicon)darwinarm64
Linux ARM(树莓派)linuxarm
Android ARM64androidarm64

修改方式:

例如将系统设置为 linux,架构为 amd64

  1. 全局修改
bash
go env -w GOOS=linux 
go env -w GOARCH=amd64
  1. 一次性修改(不改变全局)
  • PowerShell:
powershell
$env:GOOS="linux"; $env:GOARCH="amd64"; go build
  • CMD:
cmd
set GOOS=linux&set GOARCH=amd64&go build

指定名称:

参数 -o,用法

bash
go build -o myapp

注意:在windows上需要加 .exe 后缀,如:

bash
go build -o myapp.exe

跨平台构建时的命名技巧:

bash
# Linux/macOS
# GOOS=linux GOARCH=amd64
go build -o myapp-linux-amd64

# Windows
# GOOS=windows GOARCH=amd64
go build -o myapp-windows-amd64.exe

os.OpenFile()方法

1. name:文件路径

直接传入文件路径字符串,且需要确保程序对目标目录有读写权限

可以是相对路径(如 "./data.txt")或绝对路径(如 "/tmp/file.log")

go
// 当前目录下的文件
path := "data.txt"

// 绝对路径(注意操作系统的路径分隔符差异)
path := "C:\\tmp\\file.log"  // Windows
path := "/tmp/file.log"      // Unix-like

2. flag:打开模式和行为

这些标志是通过按位操作 | 组合使用的。以下是所有可用的标志及其作用:

1. 基本打开模式(必选其一)

标志说明
os.O_RDONLY0只读打开文件
os.O_WRONLY1只写打开文件
os.O_RDWR2读写打开文件

2. 文件操作行为(可选组合)

标志说明
os.O_APPEND1024追加模式(写入时定位到文件末尾)
os.O_CREATE64如果文件不存在则创建
os.O_EXCL128O_CREATE 共用时,文件必须不存在(否则报错)
os.O_SYNC4096同步I/O(写入直接刷盘,保证数据持久化)
os.O_TRUNC512打开时清空文件(如果文件已存在且可写)
os.O_DSYNC2048类似 O_SYNC,但只同步数据(不同步元数据)
os.O_TEMPORARY256(Windows特有)文件为临时文件,程序退出后自动删除

3. 常见组合示例

  • 只读打开(文件必须存在)
go
file, err := os.OpenFile("file.txt", os.O_RDONLY, 0)
  • 读写打开,不存在则创建
go
file, err := os.OpenFile("file.txt", os.O_RDWR|os.O_CREATE, 0644)
  • 只写追加(日志文件常用)
go
file, err := os.OpenFile("log.txt", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
  • 清空文件后写入
go
file, err := os.OpenFile("data.bin", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
  • 原子性创建(文件必须不存在)
go
file, err := os.OpenFile("lockfile", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0644)
if err != nil {
    fmt.Println("文件已存在,无法重复创建")
}

3. perm:文件权限

类型: os.FileMode(本质是 uint32)

写法: 使用 八进制数字 表示权限位

常用权限值:

权限值说明
0644用户可读写,其他用户只读
0666所有用户可读写
0600仅用户可读写
0755用户可读写执行,其他用户可读执行

提示

更多权限相关可以查看:Linux文件权限问题

特殊注意事项

  1. Windows系统:

    • 权限参数可能被忽略(尤其是执行权限)
    • 但建议仍按规范填写(如 0644
  2. 权限生效时机:

    • 仅在创建新文件时生效(O_CREATE 触发时)
    • 对已存在文件不会修改权限
  3. 错误处理:

go
file, err := os.OpenFile("data.txt", os.O_RDWR, 0644)
if err != nil {
    // 处理错误(如无权限、路径不存在等)
    log.Fatal(err)
}
defer file.Close() // 确保关闭文件

读取文件

1. 全部读取(小文件)

推荐方式: os.ReadFile

适用场景: 配置文件、小型文本或二进制文件(<10MB)

优点: 代码简洁,性能高

go
content, err := os.ReadFile("file.txt")
if err != nil {
    return err
}
fmt.Println(string(content))

2. 逐行读取文本文件

推荐方式: bufio.Scanner

适用场景: 日志、CSV、配置文件等文本文件

优点: 自动处理换行符,内存高效

go
file, err := os.Open("file.txt")
if err != nil {
    return err
}
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
    fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
    return err
}

优化:

调整缓冲区大小(默认 4KB,最大 64KB):

go
scanner.Buffer(make([]byte, 1024*1024), 1024*1024) // 1MB 缓冲区

适用于超大文件,避免内存问题

3. 分块读取(大文件或二进制文件)

推荐方式: bufio.Reader + 自定义缓冲区

适用场景: 大文件、二进制数据(如图片、视频)

优点: 灵活控制内存,减少系统调用

go
file, err := os.Open("largefile.bin")
if err != nil {
    return err
}
defer file.Close()

reader := bufio.NewReader(file)
buf := make([]byte, 4096) // 4KB 块
for {
    n, err := reader.Read(buf)
    if err == io.EOF {
        break
    }
    if err != nil {
        return err
    }
    process(buf[:n]) // 处理每块数据
}

注意: 适合流式处理,避免内存爆炸

4. 超大型文件(GB级)

推荐方式: 内存映射(mmap)

适用场景: 日志分析、数据库文件等

示例(第三方库):

go
file, _ := os.Open("hugefile.bin")
defer file.Close()
mmapData, _ := mmap.Map(file, mmap.RDONLY, 0)
defer mmapData.Unmap()
fmt.Println(string(mmapData))

优点: 零拷贝,性能极高

读取文件方式总结

场景推荐方式内存占用
小文件os.ReadFile
逐行文本bufio.Scanner
大文件/二进制bufio.Reader
超大文件mmap(第三方)最低

写入文件

1. 一次性写入(小文件推荐)

使用 os.WriteFile

适用于小文件,会覆盖原有内容:

go
content := []byte("Hello, 世界!")
err := os.WriteFile("./file.txt", content, 0644)
if err != nil {
    log.Fatal(err)
}

0644 是文件权限(用户可读写,其他用户只读),windows上不存在这个权限

如果文件不存在会自动创建

2. 追加写入

使用 os.OpenFileos.O_APPEND 标志:

go
file, err := os.OpenFile("file.txt", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
    log.Fatal(err)
}
defer file.Close()

_, err = file.Write([]byte("追加的内容\n"))
if err != nil {
    log.Fatal(err)
}

3. 缓冲写入(高性能写入)

使用 bufio.Writer,适合频繁写入:

go
file, err := os.Create("file.txt")
if err != nil {
    log.Fatal(err)
}
defer file.Close()

writer := bufio.NewWriter(file)
_, err = writer.WriteString("缓冲写入1\n")
if err != nil {
    log.Fatal(err)
}
_, err = writer.WriteString("缓冲写入2\n")
if err != nil {
    log.Fatal(err)
}

writer.Flush() // 必须调用,确保数据写入磁盘

Protobuf

1. 安装 protobuf 编译器 protoc

bash
# macOS (Homebrew)
brew install protobuf

# Ubuntu/Debian
sudo apt update && sudo apt install -y protobuf-compiler

# Windows (WSL 或安装 Chocolatey)
choco install protoc

检查是否安装成功:

bash
protoc --version

输出:

bash
libprotoc 31.1

2. 安装 protoc-gen-go 插件

用于编译proto文件为go代码,是一个可执行文件

bash
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest

# 旧版(已废弃)
github.com/golang/protobuf/protoc-gen-go

3. proto示例文件

proto
// hello.proto

syntax = "proto3"; // 使用proto3语法

package example;

option go_package = "your-project/proto;example";

message HelloRequest {
    string name = 1;
}

message HelloResponse {
    string message = 1;
}

4. 编译proto文件

bash
protoc --go_out=. --go_opt=paths=source_relative hello.proto

会多出一个 hello.pb.go 的文件

5. 使用proto

go
package main

import (
	"fmt"
	hello "prototest/proto"

	"google.golang.org/protobuf/proto" // 默认不存在,需要tidy
)

func main() {

	// 创建请求实例
	req := &hello.HelloRequest{
		Name: "Alice",
		Age:  18,
	}
	fmt.Println("Request:", req)

	// 序列化
	data, _ := proto.Marshal(req)
	fmt.Println("Serialized Data:", string(data))

	// 反序列化
	var res hello.HelloRequest
	_ = proto.Unmarshal(data, &res)

	fmt.Println("Deserialized Request:", &res)
}

执行 go mod tidy 自动下载依赖包,一共有两个包,建议使用新版

  • 新版:google.golang.org/protobuf
  • 旧版:github.com/golang/protobuf (已废弃)

执行main方法,打印出以下结果:

txt
Request: name:"Alice"  age:18
Serialized Data: 
Alice
Deserialized Request: name:"Alice"  age:18

序列化后有加密,有些字符显示不出来,正常现象