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 = ""
}
有疑问加站长微信联系(非本文作者)