golang第三方库之go-homedir

go-homedir是一个用于获取用户主目录的微型第三方库,代码不超过200行。源码地址:go-homedir

为什么不用os/user库?

golang标准库包含的os/user库可以获取用户的主目录,代码如下:

package main

import (
    "fmt"
    "os/user"
)

func main() {
    u, _ := user.Current()
    fmt.Println(u.HomeDir)
}

github上的解释如下:The built-in os/user package requires cgo on Darwin systems. This means that any Go code that uses that package cannot cross compile. But 99% of the time the use for os/user is just to retrieve the home directory, which we can do for the current user without cgo. This library does that, enabling cross-compilation.
Darwin操作系统上使用os/user包需要开启cgo,开启cgo意味着不能交叉编译。该库既可以获取用户的主目录,也可以交叉编译。

接口介绍

go-homedir的接口有4个:

名字 变量类型 作用
DisableCache bool false – 第一次获取主目录后修改主目录,Dir(),Expand()获取的仍是初始值;
true – 禁用缓存,实时获取主目录,比较耗时;
Dir func Dir() (string, error) 获取用户主目录
Expand func Expand(path string) (string, error) path的第一个字符是~时,替换成主目录,否则返回原目录或者error
Reset func Reset() 清空缓存的用户主目录,再次获取可以获取当前的主目录

源码分析

Dir

  • DisableCache置为false时,第一次执行Dir函数,获取当前主目录,后续获取的都是缓存值(homedirCache),这样可以节省时间;当主目录修改后,此时获得的结果有误;调用Reset函数后,清空缓存,可以获取当前主目录。因此,修改主目录后需要调用一次Reset函数,以保证获取主目录的正确性;
  • DisableCache置为true时,每次获取的都是当前的主目录,比较耗时,此时调用Reset函数无意义
var cacheLock sync.RWMutex // 读写锁
func Dir() (string, error) {
    if !DisableCache {  // DisableCache为true时,跳过该分支,获取当前主目录
        cacheLock.RLock() // 读加锁,禁止其它线程写入,可读
        cached := homedirCache
        cacheLock.RUnlock()
        if cached != "" { // 第一次或者Reset后第一次cached为空,跳过该分支
            return cached, nil 
        }
    }

    cacheLock.Lock() // 加锁,禁止其它线程读写
    defer cacheLock.Unlock()

    var result string
    var err error
    if runtime.GOOS == "windows" {
        result, err = dirWindows() // 获取Windows系统主目录
    } else {
        result, err = dirUnix() // 获取Unix-like系统主目录
    }

    if err != nil {
        return "", err
    }
    homedirCache = result // 获取的主目录存入缓存,DisableCache为false后,再次获取主目录直接从缓存读取
    return result, nil
}

Expand函数调用DIr函数,工作原理类似Dir,需要与DisableCache和Reset配合工作;

func Expand(path string) (string, error) {
    if len(path) == 0 {
        return path, nil
    }

    if path[0] != '~' {
        return path, nil //
    }

    if len(path) > 1 && path[1] != '/' && path[1] != '\\' {
        return "", errors.New("cannot expand user-specific home dir")
    }

    dir, err := Dir()
    if err != nil {
        return "", err
    }

    return filepath.Join(dir, path[1:]), nil
}

Reset主要负责清空缓存homedirCache

func Reset() {
    cacheLock.Lock()
    defer cacheLock.Unlock()
    homedirCache = ""
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注