Advanced Go Standard Library
A systematic overview of the most commonly used packages in the Go standard library, focusing on io, os, bufio, strings, time, fmt, and more.
1. Core Interfaces of the io Package
Go's I/O design revolves around several core interfaces, and almost all I/O operations are based on them.
// 最基础的两个接口
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
type Closer interface {
Close() error
}
// 组合接口
type ReadWriter interface {
Reader
Writer
}
type ReadCloser interface {
Reader
Closer
}
type WriteCloser interface {
Writer
Closer
}
Who implements these interfaces?
| Type | Reader | Writer | Closer |
|---|---|---|---|
| *os.File | Y | Y | Y |
| *bytes.Buffer | Y | Y | - |
| *strings.Reader | Y | - | - |
| net.Conn | Y | Y | Y |
| *http.Request.Body | Y | - | Y |
| *bufio.Reader | Y | - | - |
| *bufio.Writer | - | Y | - |
| *gzip.Reader | Y | - | Y |
2. Common Functions in io Package
package main
import (
"bytes"
"fmt"
"io"
"os"
"strings"
)
func main() {
// io.Copy: 从 Reader 拷贝到 Writer(最常用)
// 签名: func Copy(dst Writer, src Reader) (written int64, err error)
r := strings.NewReader("Hello, io.Copy!")
n, _ := io.Copy(os.Stdout, r) // 输出到标准输出
fmt.Printf("\n拷贝了 %d 字节\n", n)
// io.ReadAll: 读取全部内容(Go 1.16+, 替代 ioutil.ReadAll)
r2 := strings.NewReader("Read all content")
data, _ := io.ReadAll(r2)
fmt.Println(string(data))
// io.MultiReader: 将多个 Reader 串联成一个
r3 := io.MultiReader(
strings.NewReader("Part1 "),
strings.NewReader("Part2 "),
strings.NewReader("Part3"),
)
io.Copy(os.Stdout, r3) // Part1 Part2 Part3
fmt.Println()
// io.TeeReader: 读取时同时写入另一个 Writer(类似 tee 命令)
var buf bytes.Buffer
r4 := strings.NewReader("tee reader demo")
tee := io.TeeReader(r4, &buf)
io.ReadAll(tee) // 读取
fmt.Println("buf:", buf.String()) // buf 中也有了数据
// io.Pipe: 同步的内存管道(一端写另一端读)
pr, pw := io.Pipe()
go func() {
fmt.Fprint(pw, "pipe data")
pw.Close()
}()
pipeData, _ := io.ReadAll(pr)
fmt.Println("pipe:", string(pipeData))
// io.LimitReader: 限制读取字节数
r5 := strings.NewReader("only read first 5 bytes")
limited := io.LimitReader(r5, 5)
data2, _ := io.ReadAll(limited)
fmt.Println(string(data2)) // "only "
}
3. os Package
3.1 File Operations
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 创建文件
f, err := os.Create("test.txt")
if err != nil {
panic(err)
}
f.WriteString("Hello, Go!\nSecond line.\n")
f.Close()
// 读取文件(Go 1.16+)
data, err := os.ReadFile("test.txt")
if err != nil {
panic(err)
}
fmt.Println(string(data))
// 写入文件(Go 1.16+)
os.WriteFile("test2.txt", []byte("quick write"), 0644)
// 打开文件(更多控制)
f2, _ := os.OpenFile("test.txt", os.O_APPEND|os.O_WRONLY, 0644)
f2.WriteString("Appended line.\n")
f2.Close()
// 文件信息
info, _ := os.Stat("test.txt")
fmt.Printf("文件名: %s, 大小: %d, 修改时间: %v\n",
info.Name(), info.Size(), info.ModTime())
// 判断文件是否存在
if _, err := os.Stat("nonexist.txt"); os.IsNotExist(err) {
fmt.Println("文件不存在")
}
// 复制文件
src, _ := os.Open("test.txt")
dst, _ := os.Create("test_copy.txt")
io.Copy(dst, src)
src.Close()
dst.Close()
// 清理
os.Remove("test.txt")
os.Remove("test2.txt")
os.Remove("test_copy.txt")
}
3.2 Directory Operations
// 创建目录
os.Mkdir("mydir", 0755)
os.MkdirAll("a/b/c", 0755) // 递归创建
// 读取目录内容(Go 1.16+)
entries, _ := os.ReadDir(".")
for _, e := range entries {
info, _ := e.Info()
fmt.Printf("%-20s %10d %v\n", e.Name(), info.Size(), e.IsDir())
}
// 遍历目录树
filepath.WalkDir(".", func(path string, d fs.DirEntry, err error) error {
if err != nil { return err }
fmt.Println(path)
return nil
})
// 临时文件和目录
tmpFile, _ := os.CreateTemp("", "prefix-*.txt")
fmt.Println(tmpFile.Name()) // /tmp/prefix-123456.txt
tmpFile.Close()
os.Remove(tmpFile.Name())
tmpDir, _ := os.MkdirTemp("", "myapp-")
fmt.Println(tmpDir) // /tmp/myapp-789012
os.RemoveAll(tmpDir)
3.3 Environment Variables
// 获取
home := os.Getenv("HOME")
path := os.Getenv("PATH")
// 设置(只影响当前进程)
os.Setenv("MY_VAR", "hello")
// 获取,带是否存在的判断
val, ok := os.LookupEnv("MY_VAR")
if ok {
fmt.Println(val)
}
// 所有环境变量
for _, env := range os.Environ() {
fmt.Println(env)
}
3.4 Signal Handling
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
// 监听信号
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
fmt.Println("服务启动,按 Ctrl+C 退出...")
// 阻塞等待信号
sig := <-sigCh
fmt.Printf("\n收到信号: %v,开始优雅关闭...\n", sig)
// 清理资源...
fmt.Println("关闭完成")
}
4. bufio Package
bufio provides buffered I/O, reducing the number of system calls.
4.1 Scanner for Line-by-Line Reading
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
// 从字符串逐行读取
input := "第一行\n第二行\n第三行"
scanner := bufio.NewScanner(strings.NewReader(input))
for scanner.Scan() {
fmt.Println(">>", scanner.Text())
}
if err := scanner.Err(); err != nil {
fmt.Println("错误:", err)
}
// 按单词分割
wordScanner := bufio.NewScanner(strings.NewReader("hello world foo bar"))
wordScanner.Split(bufio.ScanWords)
for wordScanner.Scan() {
fmt.Println("单词:", wordScanner.Text())
}
// 读取文件(最常用的模式)
file, _ := os.Open("somefile.txt")
defer file.Close()
fileScanner := bufio.NewScanner(file)
lineNum := 0
for fileScanner.Scan() {
lineNum++
fmt.Printf("%d: %s\n", lineNum, fileScanner.Text())
}
// 处理超长行(默认 bufSize 64KB)
longScanner := bufio.NewScanner(file)
longScanner.Buffer(make([]byte, 1024*1024), 1024*1024) // 1MB buffer
}
4.2 Reader / Writer
// bufio.NewReader 带缓冲的读取
reader := bufio.NewReader(os.Stdin)
fmt.Print("请输入: ")
line, _ := reader.ReadString('\n') // 读到换行符为止
fmt.Println("你输入了:", line)
// Peek 预览但不消费
reader2 := bufio.NewReader(strings.NewReader("Hello World"))
peeked, _ := reader2.Peek(5)
fmt.Println(string(peeked)) // "Hello"(指针不移动)
full, _ := reader2.ReadString(' ')
fmt.Println(full) // "Hello "
// bufio.NewWriter 带缓冲的写入
file, _ := os.Create("output.txt")
writer := bufio.NewWriter(file)
writer.WriteString("缓冲写入第一行\n")
writer.WriteString("缓冲写入第二行\n")
writer.Flush() // 必须 Flush,否则数据可能还在缓冲区
file.Close()
5. strings Package
package main
import (
"fmt"
"strings"
)
func main() {
s := "Hello, Go World!"
// 查找
fmt.Println(strings.Contains(s, "Go")) // true
fmt.Println(strings.HasPrefix(s, "Hello")) // true
fmt.Println(strings.HasSuffix(s, "World!")) // true
fmt.Println(strings.Index(s, "Go")) // 7
fmt.Println(strings.Count(s, "l")) // 2
// 分割与合并
parts := strings.Split("a,b,c,d", ",")
fmt.Println(parts) // [a b c d]
fmt.Println(strings.Join(parts, " | ")) // a | b | c | d
fmt.Println(strings.Fields(" hello world foo ")) // [hello world foo]
// 替换与转换
fmt.Println(strings.Replace(s, "World", "Gopher", 1))
fmt.Println(strings.ReplaceAll(s, "l", "L"))
fmt.Println(strings.ToUpper(s))
fmt.Println(strings.ToLower(s))
fmt.Println(strings.Title("hello world")) // Hello World (deprecated, use cases.Title)
// 修剪
fmt.Println(strings.TrimSpace(" hello ")) // "hello"
fmt.Println(strings.Trim("***hello***", "*")) // "hello"
fmt.Println(strings.TrimLeft("000123", "0")) // "123"
fmt.Println(strings.TrimPrefix("test_func", "test_")) // "func"
fmt.Println(strings.TrimSuffix("file.go", ".go")) // "file"
// 重复
fmt.Println(strings.Repeat("ab", 3)) // "ababab"
// Map: 对每个字符应用函数
rot13 := strings.Map(func(r rune) rune {
if r >= 'a' && r <= 'z' {
return 'a' + (r-'a'+13)%26
}
return r
}, "hello")
fmt.Println(rot13) // "uryyb"
}
strings.Builder (Efficient String Concatenation)
// 低效:每次 + 都会分配新的字符串
func concatBad(n int) string {
s := ""
for i := 0; i < n; i++ {
s += "a"
}
return s
}
// 高效:使用 Builder
func concatGood(n int) string {
var b strings.Builder
b.Grow(n) // 预分配,可选但推荐
for i := 0; i < n; i++ {
b.WriteString("a")
}
return b.String()
}
// 对比: n=10000 时
// concatBad: ~50ms
// concatGood: ~0.01ms
strings.NewReader
// 把字符串变成 io.Reader
r := strings.NewReader("Hello, Reader!")
buf := make([]byte, 5)
for {
n, err := r.Read(buf)
if n > 0 {
fmt.Print(string(buf[:n]))
}
if err != nil {
break
}
}
6. bytes Package
The bytes package API almost directly corresponds to the strings package, but operates on []byte instead of string.
// bytes.Buffer 是最常用的
var buf bytes.Buffer
buf.WriteString("Hello ")
buf.Write([]byte("World"))
buf.WriteByte('!')
fmt.Println(buf.String()) // "Hello World!"
fmt.Println(buf.Len()) // 12
// 也实现了 io.Reader 和 io.Writer
io.Copy(os.Stdout, &buf)
// bytes 包函数与 strings 包对应
fmt.Println(bytes.Contains([]byte("hello"), []byte("ell"))) // true
fmt.Println(bytes.Equal([]byte("abc"), []byte("abc"))) // true
parts := bytes.Split([]byte("a,b,c"), []byte(","))
When to use bytes vs strings?
- Handling network data, file content → bytes
- Handling text strings → strings
- Needing to modify content repeatedly → bytes.Buffer
- Only needing to concatenate strings → strings.Builder
7. strconv Package
package main
import (
"fmt"
"strconv"
)
func main() {
// int <-> string
s := strconv.Itoa(42) // "42"
n, _ := strconv.Atoi("42") // 42
fmt.Println(s, n)
// 指定进制
s2 := strconv.FormatInt(255, 16) // "ff"
n2, _ := strconv.ParseInt("ff", 16, 64) // 255
fmt.Println(s2, n2)
// float <-> string
s3 := strconv.FormatFloat(3.14159, 'f', 2, 64) // "3.14"
f, _ := strconv.ParseFloat("3.14", 64) // 3.14
fmt.Println(s3, f)
// bool <-> string
s4 := strconv.FormatBool(true) // "true"
b, _ := strconv.ParseBool("true") // true
fmt.Println(s4, b)
// Quote / Unquote
fmt.Println(strconv.Quote(`hello "world"`)) // "hello \"world\""
fmt.Println(strconv.Unquote(`"hello"`)) // hello
}
8. time Package
8.1 Go's Unique Time Formatting
Go does not use YYYY-MM-DD, but instead uses a reference time: Mon Jan 2 15:04:05 MST 2006 (i.e., January 2, 2006, 3:04:05 PM).
Mnemonic: January 2, 3:04:05 PM, 2006 → 01/02 03:04:05PM '06
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
// 常用格式
fmt.Println(now.Format("2006-01-02")) // 2024-03-15
fmt.Println(now.Format("2006-01-02 15:04:05")) // 2024-03-15 14:30:00
fmt.Println(now.Format("2006/01/02 03:04 PM")) // 2024/03/15 02:30 PM
fmt.Println(now.Format(time.RFC3339)) // 2024-03-15T14:30:00+08:00
fmt.Println(now.Format("20060102")) // 20240315
// 解析时间字符串
t, _ := time.Parse("2006-01-02", "2024-12-25")
fmt.Println(t)
// 带时区解析
loc, _ := time.LoadLocation("Asia/Shanghai")
t2, _ := time.ParseInLocation("2006-01-02 15:04:05", "2024-12-25 20:00:00", loc)
fmt.Println(t2)
}
8.2 Duration
// Duration 本质是 int64(纳秒数)
d := 5 * time.Second
fmt.Println(d) // 5s
fmt.Println(d.Seconds()) // 5
fmt.Println(d.Milliseconds()) // 5000
// 时间计算
now := time.Now()
future := now.Add(24 * time.Hour)
past := now.Add(-2 * time.Hour)
diff := future.Sub(now)
fmt.Println("差值:", diff) // 24h0m0s
// Since 和 Until
start := time.Now()
// ... 做一些操作
elapsed := time.Since(start) // 等价于 time.Now().Sub(start)
fmt.Printf("耗时: %v\n", elapsed)
remaining := time.Until(future) // 等价于 future.Sub(time.Now())
fmt.Println("距离:", remaining)
8.3 Timer and Ticker
// Timer: 一次性定时器
timer := time.NewTimer(2 * time.Second)
fmt.Println("等待 2 秒...")
<-timer.C
fmt.Println("Timer 触发!")
// 取消 Timer
timer2 := time.NewTimer(5 * time.Second)
go func() {
<-timer2.C
fmt.Println("不会执行")
}()
timer2.Stop() // 取消
// time.After: Timer 的简写(注意循环中不要用,会泄漏)
select {
case <-time.After(1 * time.Second):
fmt.Println("超时")
}
// Ticker: 周期性定时器
ticker := time.NewTicker(500 * time.Millisecond)
defer ticker.Stop() // 必须 Stop,否则泄漏
count := 0
for t := range ticker.C {
fmt.Println("Tick:", t.Format("05.000"))
count++
if count >= 5 {
break
}
}
8.4 Time Comparison
t1 := time.Now()
t2 := t1.Add(time.Hour)
fmt.Println(t1.Before(t2)) // true
fmt.Println(t1.After(t2)) // false
fmt.Println(t1.Equal(t1)) // true
// 零值检查
var t3 time.Time
fmt.Println(t3.IsZero()) // true
9. fmt Package Formatting Verbs
type User struct {
Name string
Age int
}
u := User{"Alice", 30}
p := &u
// 通用
fmt.Printf("%v\n", u) // {Alice 30} 值的默认格式
fmt.Printf("%+v\n", u) // {Name:Alice Age:30} 带字段名
fmt.Printf("%#v\n", u) // main.User{Name:"Alice", Age:30} Go语法表示
fmt.Printf("%T\n", u) // main.User 类型
// 整数
fmt.Printf("%d\n", 42) // 42 十进制
fmt.Printf("%b\n", 42) // 101010 二进制
fmt.Printf("%o\n", 42) // 52 八进制
fmt.Printf("%x\n", 42) // 2a 十六进制小写
fmt.Printf("%X\n", 42) // 2A 十六进制大写
fmt.Printf("%05d\n", 42) // 00042 前导零填充
// 浮点
fmt.Printf("%f\n", 3.14) // 3.140000 默认
fmt.Printf("%.2f\n", 3.14) // 3.14 精度2
fmt.Printf("%e\n", 3.14) // 3.140000e+00 科学计数法
fmt.Printf("%g\n", 3.14) // 3.14 紧凑表示
// 字符串
fmt.Printf("%s\n", "hello") // hello
fmt.Printf("%q\n", "hello") // "hello" 带引号
fmt.Printf("%x\n", "abc") // 616263 十六进制
// 指针
fmt.Printf("%p\n", p) // 0xc000010020
// 宽度与对齐
fmt.Printf("|%-10s|%10s|\n", "left", "right")
// |left | right|
// 错误包装(Go 1.13+, 配合 fmt.Errorf)
err := fmt.Errorf("操作失败: %w", io.EOF)
fmt.Println(err) // 操作失败: EOF
// Sprintf 返回字符串(不打印)
s := fmt.Sprintf("Name: %s, Age: %d", u.Name, u.Age)
// Fprintf 写入 Writer
fmt.Fprintf(os.Stderr, "错误: %v\n", err)
// Stringer 接口:自定义 %v 输出
// 实现 String() string 方法即可
func (u User) String() string {
return fmt.Sprintf("%s(%d岁)", u.Name, u.Age)
}
// fmt.Println(u) -> Alice(30岁)
10. log/slog Structured Logging (Go 1.21+)
package main
import (
"log/slog"
"os"
)
func main() {
// 默认文本格式
slog.Info("服务启动", "port", 8080, "env", "production")
// 输出: 2024/03/15 14:30:00 INFO 服务启动 port=8080 env=production
// JSON 格式(适合日志收集系统)
jsonHandler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug,
})
logger := slog.New(jsonHandler)
logger.Debug("调试信息", "module", "auth")
logger.Info("用户Login", "user_id", 12345, "ip", "192.168.1.1")
logger.Warn("磁盘空间不足", "usage", "85%")
logger.Error("数据库连接失败", "error", "connection refused", "host", "db.example.com")
// 输出JSON: {"time":"...","level":"INFO","msg":"用户Login","user_id":12345,"ip":"192.168.1.1"}
// 带固定字段的子 logger
reqLogger := logger.With("request_id", "abc-123", "method", "POST")
reqLogger.Info("处理请求") // 自动带上 request_id 和 method
reqLogger.Info("请求完成", "status", 200, "duration_ms", 42)
// 分组
logger.Info("请求详情",
slog.Group("request",
slog.String("method", "POST"),
slog.String("path", "/api/users"),
),
slog.Group("response",
slog.Int("status", 200),
slog.Int("bytes", 1234),
),
)
// JSON: {"msg":"请求详情","request":{"method":"POST","path":"/api/users"},"response":{"status":200,"bytes":1234}}
// LogValuer 接口:自定义类型的日志输出
// 实现 LogValue() slog.Value 方法
}
Quick Reference
| Package | Core Purpose | Most Common Functions/Types |
|---|---|---|
| io | I/O Abstraction Interfaces | Reader/Writer, Copy, ReadAll, Pipe |
| os | Operating System Interaction | Open/Create, ReadFile/WriteFile, Stat, Getenv, Signal |
| bufio | Buffered I/O | Scanner(逐行), NewReader, NewWriter |
| strings | String Operations | Contains, Split, Join, Replace, Builder |
| bytes | Byte Slice Operations | Buffer, Contains, Equal |
| strconv | Type Conversion | Itoa/Atoi, FormatFloat/ParseFloat |
| time | Time Handling | Now, Parse, Format("2006-01-02"), Duration, Timer/Ticker |
| fmt | Formatted I/O | Printf(%v/%+v/%#v/%T), Sprintf, Errorf(%w) |
| log/slog | Structured Logging | Info/Warn/Error, With, Group, JSONHandler |
主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://walker-learn.xyz/archives/6722