Skip to content

Daily Study

更新: 6/5/2025 字数: 0 字 时长: 0 分钟

Daily Plan

#todo

Lab1_MapReduce

go json相关

详细分析一下如下代码

go
package main

  

import (

    "encoding/json"

    "fmt"

    "log"

    "strings"

)

  

type Animal int

  

const (

    Unknown Animal = iota

    Gopher

    Zebra

)

  

func (a *Animal) UnmarshalJSON(b []byte) error {

    var s string

    if err := json.Unmarshal(b, &s); err != nil {

        return err

    }

    switch strings.ToLower(s) {

    default:

        *a = Unknown

    case "gopher":

        *a = Gopher

    case "zebra":

        *a = Zebra

    }

  

    return nil

}

  

func (a Animal) MarshalJSON() ([]byte, error) {

    var s string

    switch a {

    default:

        s = "unknown"

    case Gopher:

        s = "gopher"

    case Zebra:

        s = "zebra"

    }

  

    return json.Marshal(s)

}

  

func main() {

    blob := `["gopher","armadillo","zebra","unknown","gopher","bee","gopher","zebra"]`

    var zoo []Animal

    if err := json.Unmarshal([]byte(blob), &zoo); err != nil {

        log.Fatal(err)

    }

  

    census := make(map[Animal]int)

    for _, animal := range zoo {

        census[animal] += 1

    }

  

    fmt.Printf("Zoo Census:\n* Gophers: %d\n* Zebras:  %d\n* Unknown: %d\n",

        census[Gopher], census[Zebra], census[Unknown])

  

}
  • main函数中blob 使用反引号,避免转义 JSON 字符串中的双引号,保持 JSON 格式的可读性
  • []byte数组等价于 []uint8,是一种字节切片类型,如下
go
str := "Hello"

bytes := []byte(str)  // 字符串转换为字节切片

fmt.Println(bytes)    // 输出: [72 101 108 108 111]
  • json解析需要 []byte,是因为 func Unmarshal(data []byte, v interface{}) error,有如下三个优点:
    • 性能考虑:避免字符串的不必要复制
    • 内存效率:可以直接处理字节数据
    • 通用性:可以处理任何来源的字节数据(文件、网络等)

os相关

1. 文件操作

go
// 打开文件(只读)

file, err := os.Open(reply.TaskName)

defer file.Close()

// 创建新文件

ofile, err := os.Create(oname)

// 以追加模式打开文件

ofile, err := os.OpenFile(oname, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)

2. 文件状态检查

go

// 检查文件是否存在

if _, err := os.Stat(oname); os.IsNotExist(err) {

    // 文件不存在

    ofile, _ = os.Create(oname)

else {

    // 文件存在,以追加模式打开

    ofile, _ = os.OpenFile(oname, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)

}

3. 目录操作

go
// 读取目录内容

files, err := os.ReadDir(path)

if err != nil {

    return err

}

// 遍历目录中的文件

for _, file := range files {

    if file.IsDir() {

        continue  // 跳过子目录

    }

    fileName := file.Name()

    // 处理文件...

}

4. 文件删除

go
// 删除文件

err := os.Remove(filePath)

if err != nil {

    return err

}

// 删除 socket 文件

os.Remove(sockname)

### 5. 系统信息

// 获取用户ID

+= strconv.Itoa(os.Getuid())

// 程序退出

os.Exit(0)    // 正常退出

os.Exit(-1)   // 异常退出

Regexp

正则表达式书写:

// 基本字符匹配
^     // 行开始
$     // 行结束  
.     // 任意字符(除换行符)
*     // 前面字符0次或多次
+     // 前面字符1次或多次
?     // 前面字符0次或1次
\d    // 数字字符 [0-9]
\w    // 单词字符 [a-zA-Z0-9_]
\s    // 空白字符

// 字符组

[abc]     // 匹配 a、b 或 c

[a-z]     // 匹配小写字母

[^abc]    // 不匹配 a、b、c

  

// 量词

{n}       // 恰好 n 次

{n,}      // 至少 n 次  

{n,m}     // n 到 m 次

  

// 示例:匹配IP地址

ipPattern := `^(\d{1,3}\.){3}\d{1,3}$`

具体实现,匹配MapReduce文件名:

go

import (

    "fmt"

    "regexp"

)

  

// 匹配 mr-out-{mapId}-{reduceId} 格式的文件

func matchMapOutputFiles(mapId int) *regexp.Regexp {

    // 使用 \d+ 匹配一个或多个数字

    pattern := fmt.Sprintf(`^mr-out-%d-\d+$`, mapId)

    return regexp.MustCompile(pattern)

}

  

// 匹配 mr-out-{任意数字}-{特定reduceId} 格式的文件

func matchReduceInputFiles(reduceId int) *regexp.Regexp {

    pattern := fmt.Sprintf(`^mr-out-\d+-%d$`, reduceId)

    return regexp.MustCompile(pattern)

}

菜就多练

本站访客数 人次 本站总访问量