10、字符串、日期时间、文件操作

10、字符串、日期时间、文件操作


字符串与格式化(fmt、strconv、strings、bytes)

fmt —— 格式化输入输出

fmt 包提供格式化 I/O,主要用于打印到控制台、格式化字符串等。

常用输出函数

  • Print / Printf / Println:输出到标准输出。
  • Sprintf:格式化并返回字符串,不直接打印。
  • Fprintf:写入指定 io.Writer(如文件、网络连接)。
name := "Alice"
age := 30
s := fmt.Sprintf("%s is %d years old", name, age) // "Alice is 30 years old"
fmt.Println(s)

常用格式化动词

动词 含义
%v 默认格式(值的自然形式)
%+v 结构体时添加字段名
%#v Go 语法表示
%T 值的类型
%d 十进制整数
%s 字符串
%q 带引号的字符串
%f 浮点数
%t 布尔值
%p 指针地址

输入函数

  • fmt.Scan / Scanf / Scanln:从标准输入读取。
  • fmt.Fscan 系列:从 io.Reader 读取。
  • fmt.Sscan 系列:从字符串读取。

strconv —— 字符串与基本类型转换

strconv 提供字符串和数字、布尔等类型的相互转换,比 fmt 效率更高,适合大量转换。

  • 数字转字符串
s := strconv.Itoa(42)                 // "42"
s = strconv.FormatInt(255, 16)        // "ff"(十六进制)
s = strconv.FormatFloat(3.14, 'f', 2, 64) // "3.14"
  • 字符串转数字
i, err := strconv.Atoi("42")          // 42, nil
i64, err := strconv.ParseInt("ff", 16, 64) // 255, nil
f, err := strconv.ParseFloat("3.14", 64)   // 3.14, nil
  • 布尔与字符串互转
b, _ := strconv.ParseBool("true")     // true
s := strconv.FormatBool(true)         // "true"
  • 引号处理
    • strconv.Quote(s):返回带引号的字符串,转义内部特殊字符。
    • strconv.Unquote(s):解析带引号的字符串。

strings —— 字符串操作

strings 包提供大量高效字符串函数,不会修改原字符串(字符串不可变),总是返回新字符串。

  • 检查与比较
strings.Contains("golang", "go")      // true
strings.HasPrefix("main.go", "main") // true
strings.HasSuffix("main.go", ".go")  // true
strings.EqualFold("Go", "go")        // true(忽略大小写)
  • 查找
strings.Index("hello", "ll")         // 2
strings.LastIndex("hello", "l")      // 3
strings.Count("hello", "l")          // 2
  • 分割与连接
parts := strings.Split("a,b,c", ",")  // ["a","b","c"]
joined := strings.Join(parts, "-")    // "a-b-c"
// 按空格切割(连续空格被视为一个分隔符)
words := strings.Fields(" hello  world ") // ["hello","world"]
  • 大小写转换
strings.ToUpper("go")    // "GO"
strings.ToLower("GO")    // "go"
strings.Title("go lang") // "Go Lang"(已废弃,推荐使用 cases 包)
  • 修剪
strings.TrimSpace(" hello ")          // "hello"
strings.Trim("!!hello!!", "!")       // "hello"
strings.TrimLeft("/path/", "/")      // "path/"
  • 替换
r := strings.Replace("oink oink oink", "oink", "moo", 2) // "moo moo oink"
r = strings.ReplaceAll("oink oink", "oink", "moo")       // "moo moo"
  • Builder(高效字符串拼接)
var b strings.Builder
b.WriteString("Hello")
b.WriteString(" World")
result := b.String() // "Hello World"

bytes —— 字节切片操作

bytes 包提供了与 strings 相似的操作,但面向 []byte 类型,适合处理二进制数据或高效字符串操作。

  • 基本操作
b := []byte("hello")
bytes.Contains(b, []byte("ll"))     // true
bytes.Equal(b, []byte("hello"))    // true
bytes.Index(b, []byte("e"))        // 1
  • 分割与连接
parts := bytes.Split([]byte("a,b,c"), []byte(","))
joined := bytes.Join(parts, []byte("-")) // "a-b-c"
  • 大小写、修剪、替换

类比 strings,如 bytes.ToUpper、bytes.TrimSpace、bytes.ReplaceAll。

  • Buffer(可读写字节缓冲区)
var buf bytes.Buffer
buf.WriteString("Hello")
buf.WriteByte(' ')
buf.Write([]byte("World"))
fmt.Println(buf.String()) // "Hello World"

bytes.Buffer 实现了 io.Reader 和 io.Writer,非常适合在内存中构建或处理数据流。

字符串处理工具实战

目标:编写一个工具,统计单词频率、替换敏感词、提取数字等,综合运用上述包。

package main

import (
    "fmt"
    "strconv"
    "strings"
    "unicode"
)

// WordStats 统计每个单词出现次数
func WordStats(text string) map[string]int {
    counts := make(map[string]int)
    words := strings.Fields(text)
    for _, w := range words {
        // 去除标点符号,只保留字母数字(简化)
        cleaned := strings.TrimFunc(w, func(r rune) bool {
            return !unicode.IsLetter(r) && !unicode.IsNumber(r)
        })
        cleaned = strings.ToLower(cleaned)
        if cleaned != "" {
            counts[cleaned]++
        }
    }
    return counts
}

// ReplaceSensitive 将敏感词替换为 ***
func ReplaceSensitive(text string, keywords []string) string {
    result := text
    for _, kw := range keywords {
        result = strings.ReplaceAll(result, kw, "***")
    }
    return result
}

// ExtractNumbers 提取字符串中的所有整数
func ExtractNumbers(text string) []int {
    var nums []int
    fields := strings.Fields(text)
    for _, f := range fields {
        // 去除可能的逗号或点
        cleaned := strings.TrimRight(f, ",.")
        if n, err := strconv.Atoi(cleaned); err == nil {
            nums = append(nums, n)
        }
    }
    return nums
}

func main() {
    sample := "The quick brown fox jumps over the lazy dog. Fox is quick!"
    stats := WordStats(sample)
    fmt.Println("Word frequencies:", stats)

    filtered := ReplaceSensitive("badword1 and badword2 are not allowed", []string{"badword1", "badword2"})
    fmt.Println("Filtered:", filtered)

    nums := ExtractNumbers("There are 12 apples and 34 oranges, totaling 46.")
    fmt.Println("Numbers:", nums) // [12 34 46]
}

OS、IO、文件读写与日志分析器

os —— 操作系统交互

os 包提供平台无关的操作系统功能,包括文件操作、环境变量、进程管理等。

文件操作

// 打开文件(只读)
f, err := os.Open("file.txt")

// 创建或打开文件(读写、权限)
f, err := os.OpenFile("output.txt", os.O_CREATE|os.O_WRONLY, 0644)

// 创建文件
f, err := os.Create("new.txt")

// 读取整个文件
data, err := os.ReadFile("file.txt")

// 写入文件
err := os.WriteFile("file.txt", data, 0644)

// 检查错误(os.IsNotExist)
if _, err := os.Stat("file.txt"); os.IsNotExist(err) {
    fmt.Println("File does not exist")
}

目录与环境

os.Mkdir("dir", 0755)
os.MkdirAll("path/to/dir", 0755) // 递归创建
os.Getwd()
os.Chdir("dir")
home := os.Getenv("HOME")

io —— 通用 I/O 抽象

io 包提供了 io.Reader 和 io.Writer 等核心接口,是所有流处理的基础。

type Reader interface {
    Read(p []byte) (n int, err error)
}
type Writer interface {
    Write(p []byte) (n int, err error)
}

常用函数:

  • io.ReadAll(r):读取全部数据。
  • io.Copy(dst, src):从源复制到目标,直到 EOF。
  • io.Pipe():创建内存管道。

bufio —— 缓冲 I/O

bufio 包装 io.Reader 或 io.Writer,提供缓冲读写,尤其适合逐行处理大文件。

f, _ := os.Open("large.log")
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
    line := scanner.Text()
    // 处理每一行
}
if err := scanner.Err(); err != nil {
    // 处理错误
}

bufio.Scanner 默认按行分割(ScanLines),也可以自定义分割函数。

日志文件分析器实战

需求:读取服务器日志文件,统计包含 “ERROR” 的行数,并列出最近的 5 条错误信息。

日志格式示例:

2025-01-01 10:00:00 INFO Starting server
2025-01-01 10:01:00 ERROR failed to connect to database
2025-01-01 10:02:00 WARN slow query detected
2025-01-01 10:03:00 ERROR timeout

代码实现:

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

type LogEntry struct {
    LineNumber int
    Content    string
}

func AnalyzeLog(filePath string) (errorCount int, lastErrors []LogEntry, err error) {
    f, err := os.Open(filePath)
    if err != nil {
        return 0, nil, fmt.Errorf("open file: %w", err)
    }
    defer f.Close()

    scanner := bufio.NewScanner(f)
    lineNum := 0
    var errors []LogEntry

    for scanner.Scan() {
        lineNum++
        line := scanner.Text()
        if strings.Contains(line, "ERROR") {
            errorCount++
            errors = append(errors, LogEntry{lineNum, line})
        }
    }
    if err := scanner.Err(); err != nil {
        return 0, nil, fmt.Errorf("scan file: %w", err)
    }

    // 取最后5条错误(若不足5条则全部)
    if len(errors) > 5 {
        errors = errors[len(errors)-5:]
    }
    return errorCount, errors, nil
}

func main() {
    count, lastErrors, err := AnalyzeLog("server.log")
    if err != nil {
        fmt.Fprintf(os.Stderr, "Error: %v\n", err)
        os.Exit(1)
    }
    fmt.Printf("Total ERROR count: %d\n", count)
    fmt.Println("Last error entries:")
    for _, e := range lastErrors {
        fmt.Printf("  Line %d: %s\n", e.LineNumber, e.Content)
    }
}

time 与日期处理

time 包提供时间测量、显示和时区转换功能。

时间的基本概念

  • time.Time:表示一个时间点,包含时区信息。
  • time.Duration:表示纳秒级的时间间隔。

获取时间

now := time.Now()                // 当前本地时间
utcNow := time.Now().UTC()      // UTC 时间

构造时间

t := time.Date(2025, time.January, 1, 12, 0, 0, 0, time.UTC)

格式化与解析

Go 使用特定的参考时间 Mon Jan 2 15:04:05 MST 2006(即 2006-01-02 15:04:05)来定义格式布局,必须用这个参考时间的数字表示。

格式化(Time to string):

t := time.Now()
fmt.Println(t.Format("2006-01-02 15:04:05"))
fmt.Println(t.Format("2006/01/02 03:04:05 PM"))
fmt.Println(t.Format(time.RFC3339))

解析(String to time):

s := "2025-01-01 12:00:00"
t, err := time.Parse("2006-01-02 15:04:05", s)
// 带时区解析
t, err = time.Parse(time.RFC3339, "2025-01-01T12:00:00Z")

时区转换

loc, _ := time.LoadLocation("America/New_York")
nyTime := time.Now().In(loc)
fmt.Println(nyTime.Format("2006-01-02 15:04:05 MST"))

时间运算

now := time.Now()
future := now.Add(24 * time.Hour)       // 加一天
diff := future.Sub(now)                 // time.Duration
fmt.Println(diff.Hours())

时间戳与转换

// 获取 Unix 时间戳(秒、毫秒、纳秒)
sec := time.Now().Unix()
msec := time.Now().UnixMilli()
nsec := time.Now().UnixNano()

// 从时间戳创建时间
t := time.Unix(sec, 0)

实战 —— 倒计时程序与时间戳转换工具

倒计时程序

package main

import (
    "fmt"
    "time"
)

func main() {
    target := time.Date(2026, time.January, 1, 0, 0, 0, 0, time.Local)
    fmt.Printf("Countdown to %s\n", target.Format("2006-01-02 15:04:05"))

    for {
        remaining := time.Until(target)
        if remaining <= 0 {
            fmt.Println("Time's up!")
            break
        }
        days := int(remaining.Hours() / 24)
        hours := int(remaining.Hours()) % 24
        minutes := int(remaining.Minutes()) % 60
        seconds := int(remaining.Seconds()) % 60
        fmt.Printf("\r%02d days %02d:%02d:%02d", days, hours, minutes, seconds)
        time.Sleep(1 * time.Second)
    }
}

时间戳转换工具

package main

import (
    "fmt"
    "os"
    "strconv"
    "time"
)

func main() {
    if len(os.Args) < 2 {
        fmt.Println("Usage: tsconv <unix_timestamp>  or tsconv <ISO8601 string>")
        return
    }
    input := os.Args[1]

    // 尝试解析为 Unix 时间戳(秒)
    if ts, err := strconv.ParseInt(input, 10, 64); err == nil {
        t := time.Unix(ts, 0)
        fmt.Println("Local:", t.Format("2006-01-02 15:04:05"))
        fmt.Println("UTC:", t.UTC().Format(time.RFC3339))
        return
    }

    // 尝试解析为常见格式字符串
    layouts := []string{
        time.RFC3339,
        "2006-01-02 15:04:05",
        "2006-01-02",
    }
    for _, layout := range layouts {
        if t, err := time.Parse(layout, input); err == nil {
            fmt.Println("Unix timestamp:", t.Unix())
            fmt.Println("Local:", t.Local().Format("2006-01-02 15:04:05"))
            return
        }
    }
    fmt.Println("Unrecognized time format")
}

核心要点速记

  • fmt:格式化打印和扫描,%v、%+v、%#v 常用。
  • strconv:数字/字符串互转,Atoi、Itoa、ParseFloat。
  • strings:查找、分割、替换、修剪,Builder 高效拼接。
  • bytes:[]byte 版字符串操作,Buffer 充当可读写缓冲区。
  • os:文件/目录操作、环境变量、进程退出。
  • io:Reader/Writer 接口,Copy、ReadAll。
  • bufio:缓冲扫描,Scanner 逐行读取大文件。
  • time:参考时间 2006-01-02 15:04:05 定义格式,时区转换、时间戳、倒计时。
posted @ 2026-09-23 16:37  爱喝奶茶的CC怪  阅读(8)  评论(0)    收藏  举报