内容简介:今天我们来看一个很小,很实用的库实际上,使用标准库那么为什么还要
简介
今天我们来看一个很小,很实用的库 go-homedir 。顾名思义, go-homedir 用来获取用户的主目录。
实际上,使用标准库 os/user 我们也可以得到这个信息:
package main
import (
"fmt"
"log"
"os/user"
)
func main() {
u, err := user.Current()
if err != nil {
log.Fatal(err)
}
fmt.Println("Home dir:", u.HomeDir)
}
那么为什么还要 go-homedir 库?
在 Darwin 系统上,标准库 os/user 的使用需要 cgo。所以,任何使用 os/user 的代码都不能交叉编译。
但是,大多数人使用 os/user 的目的仅仅只是想获取主目录。因此, go-homedir 库出现了。
快速使用
go-homedir 是第三方包,使用前需要先安装:
$ go get github.com/mitchellh/go-homedir
使用非常简单:
package main
import (
"fmt"
"log"
"github.com/mitchellh/go-homedir"
)
func main() {
dir, err := homedir.Dir()
if err != nil {
log.Fatal(err)
}
fmt.Println("Home dir:", dir)
dir = "~/golang/src"
expandedDir, err := homedir.Expand(dir)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Expand of %s is: %s\n", dir, expandedDir)
}
go-homedir 有两个功能:
-
Dir:获取用户主目录; -
Expand:将路径中的第一个~扩展成用户主目录。
高级用法
由于 Dir 的调用可能涉及一些系统调用和外部执行命令,多次调用费性能。所以 go-homedir 提供了缓存的功能。默认情况下,缓存是开启的。
我们也可以将 DisableCache 设置为 false 来关闭它。
package main
import (
"fmt"
"log"
"github.com/mitchellh/go-homedir"
)
func main() {
homedir.DisableCache = false
dir, err := homedir.Dir()
if err != nil {
log.Fatal(err)
}
fmt.Println("Home dir:", dir)
}
使用缓存时,如果程序运行中修改了主目录,再次调用 Dir 还是返回之前的目录。如果需要获取最新的主目录,可以先调用 Reset 清除缓存。
实现
go-homedir 源码只有一个文件 homedir.go ,今天我们大概看一下 Dir 的实现,去掉缓存相关代码:
func Dir() (string, error) {
var result string
var err error
if runtime.GOOS == "windows" {
result, err = dirWindows()
} else {
// Unix-like system, so just assume Unix
result, err = dirUnix()
}
if err != nil {
return "", err
}
return result, nil
}
判断当前的系统是 windows 还是类 Unix,分别调用不同的方法。先看 windows 的,比较简单:
func dirWindows() (string, error) {
// First prefer the HOME environmental variable
if home := os.Getenv("HOME"); home != "" {
return home, nil
}
// Prefer standard environment variable USERPROFILE
if home := os.Getenv("USERPROFILE"); home != "" {
return home, nil
}
drive := os.Getenv("HOMEDRIVE")
path := os.Getenv("HOMEPATH")
home := drive + path
if drive == "" || path == "" {
return "", errors.New("HOMEDRIVE, HOMEPATH, or USERPROFILE are blank")
}
return home, nil
}
流程如下:
- 读取环境变量
HOME,如果不为空,返回这个值; - 读取环境变量
USERPROFILE,如果不为空,返回这个值; - 读取环境变量
HOMEDRIVE和HOMEPATH,如果两者都不为空,拼接这两个值返回。
类 Unix 系统的实现稍微复杂一点:
func dirUnix() (string, error) {
homeEnv := "HOME"
if runtime.GOOS == "plan9" {
// On plan9, env vars are lowercase.
homeEnv = "home"
}
// First prefer the HOME environmental variable
if home := os.Getenv(homeEnv); home != "" {
return home, nil
}
var stdout bytes.Buffer
// If that fails, try OS specific commands
if runtime.GOOS == "darwin" {
cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`)
cmd.Stdout = &stdout
if err := cmd.Run(); err == nil {
result := strings.TrimSpace(stdout.String())
if result != "" {
return result, nil
}
}
} else {
cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid()))
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
// If the error is ErrNotFound, we ignore it. Otherwise, return it.
if err != exec.ErrNotFound {
return "", err
}
} else {
if passwd := strings.TrimSpace(stdout.String()); passwd != "" {
// username:password:uid:gid:gecos:home:shell
passwdParts := strings.SplitN(passwd, ":", 7)
if len(passwdParts) > 5 {
return passwdParts[5], nil
}
}
}
}
// If all else fails, try the shell
stdout.Reset()
cmd := exec.Command("sh", "-c", "cd && pwd")
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
return "", err
}
result := strings.TrimSpace(stdout.String())
if result == "" {
return "", errors.New("blank output when reading home directory")
}
return result, nil
}
流程如下:
- 先读取环境变量
HOME(注意 plan9 系统上为home),如果不为空,返回这个值; - 使用
getnet命令查看系统的数据库中的相关记录,我们知道passwd文件中存储了用户信息,包括用户的主目录。使用getent命令查看passwd中当前用户的那条记录,然后从中找到主目录部分返回; - 如果上一个步骤失败了,我们知道
cd后不加参数是直接切换到用户主目录的,而pwd可以显示当前目录。那么就可以结合这两个命令返回主目录。
这里分析源码并不是表示使用任何库都要熟悉它的源码,毕竟使用库就是为了方便开发。
但是源码是我们学习和提高的一个非常重要的途径。我们在使用库遇到问题的时候也要有能力从文档或甚至源码中查找原因。
参考
- home-dir GitHub 仓库
我
欢迎关注我的微信公众号【GoUpUp】,共同学习,一起进步~
本文由博客一文多发平台 OpenWrite 发布!
以上所述就是小编给大家介绍的《Go 每日一库之 go-homedir》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Python语言程序设计
[美]梁勇(Lang Y. D.) / 李娜 / 机械工业出版社 / 2015-4 / 79.00元
本书采用“问题驱动”、“基础先行”和“实例和实践相结合”的方式,讲述如何使用Python语言进行程序设计。本书首先介绍Python程序设计的基本概念,接着介绍面向对象程序设计方法,最后介绍算法与数据结构方面的内容。为了帮助学生更好地掌握相关知识,本书每章都包括以下模块:学习目标,引言,关键点,检查点,问题,本章总结,测试题,编程题,注意、提示和警告。 本书可以作为高等院校计算机及相关专业Py......一起来看看 《Python语言程序设计》 这本书的介绍吧!