环境变量
go 中读取环境变量是通过 os.Getenv
db := os.Getenv("DB")
fmt.Println(db)
环境变量存储位置是看你的终端
如果你的终端是 zsh 那么你可以在 ~/.zshrc 中设置,如果是 bash 那么你可以在 ~/.bashrc 中设置
临时环境变量设置
$ export DB=postgres
$ go run . # postgres
$ DB=mysql go run . # mysql
批量读取环境变量
批量读取环境变量可以使用 "github.com/caarlos0/env" 包
通过定义一个结构体,然后通过 env.Parse 方法将环境变量解析到结构体中,代码如下:
type Config struct {
DB string `env:"DB"`
LogLevel string `env:"LogLevel"`
RedisHost string `env:"RedisHost"`
RedisPort string `env:"RedisPort"`
}
func main() {
cfg := Config{}
// 解析环境变量
if err := env.Parse(&cfg); err != nil {
fmt.Printf("%+v\n", err)
}
fmt.Printf("%v\n", cfg)
}
文件读取
os.Open 和 os.OpenFile 用于打开文件,os.Open 只读方式打开文件,os.OpenFile 可以指定打开方式
读取文件通过 os.Open 方法,然后通过 file.Read 方法将文件内容读取到指定的缓冲区中
buf是为读取文件的最大字节file.Read返回读取的字节数和错误信息
func main() {
file, err := os.Open("example.csv")
if err != nil {
panic(err)
}
defer file.Close()
buf := make([]byte, 100)
n, err := file.Read(buf) // 将文件内容读取到 buf 中,buf 的长度是读取的最大长度,n 是读取的字节数
if err != nil {
panic(err)
}
fmt.Println(n)
fmt.Println(string(buf[:n])) // 如果 buffer 太大,可能会有多余的字符,所以需要通过 n 来截取
}
这种方式读取文件是一次性读取文件的所有内容,如果文件过大,可能会导致内存溢出
如何解决这个问题呢?
循环读取文件
通过循环读取文件,每次读取文件的一部分,直到文件读取完毕,代码如下:
func main() {
file, err := os.Open("example.csv")
if err != nil {
panic(err)
}
defer file.Close()
// buf 设置小一点,每次读取文件的一部分
buf := make([]byte, 1024)
for {
n, err := file.Read(buf)
if err != nil {
// 如果读取到文件末尾,那么就退出循环
if err == io.EOF {
break
}
panic(err)
}
fmt.Println(string(buf[:n]))
fmt.Println(n)
}
}
这种方式有个问题:每次读取的字节数是固定的,可能会导致文件内容被截取
readAll
io.ReadAll 可以一次性读取文件的所有内容,代码如下:
func main() {
file, err := os.Open("example.csv")
if err != nil {
panic(err)
}
defer file.Close()
bytes, err := io.ReadAll(file)
if err != nil {
panic(err)
}
fmt.Println(string(bytes))
}
这种方式也有问题,如果文件过大,可能会导致内存溢出
按行读取文件
通过 bufio.NewReader 可以按行读取文件,代码如下:
func main() {
file, err := os.Open("example.csv")
if err != nil {
panic(err)
}
defer file.Close()
reader := bufio.NewReader(file)
for {
line, _, err := reader.ReadLine()
if err != nil {
if err == io.EOF {
break
}
panic(err)
}
fmt.Println(string(line))
}
}
这种方式可以按行读取文件,就不会出现内存溢出的问题
文件写入
os 文件操作:
os.O_TRUNC清空文件内容os.O_APPEND在文件末尾追加内容os.O_CREATE创建文件os.O_RDONLY只读os.O_WRONLY只写os.O_RDWR读写
func main() {
file, err := os.OpenFile("example.csv", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
panic(err)
}
defer file.Close()
for i := 0; i < 20; i++ {
_, err := file.WriteString(fmt.Sprintf("%d\n", i))
if err != nil {
panic(err)
}
}
}
使用游标
写完文件后,如果想要读取文件,需要将游标移动到文件的开始位置
- 因为写文件时,游标会移动到文件的末尾
func main() {
file, err := os.OpenFile("example.csv", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
panic(err)
}
defer file.Close()
for i := 0; i < 20; i++ {
_, err := file.WriteString(fmt.Sprintf("%d\n,", i))
if err != nil {
panic(err)
}
}
// 移到开始的位置
file.Seek(0, io.SeekStart)
reader := bufio.NewReader(file)
for {
line, _, err := reader.ReadLine()
if err != nil {
if err == io.EOF {
return
}
panic(err)
}
fmt.Println(string(line))
}
}
递归读取文件夹
os.ReadDir 读出来的文件只是目录下的文件名,还需要手动拼接路径
在不同的操作系统中,路径的格式是不一样的,在 linux 中是以 / 拼接,而在 windows 中是以 \\ 拼接
filepath.Join 可以根据不同的操作系统,拼接符合操作系统的路径
func readDirRecursively(dir string) error {
entries, err := os.ReadDir(dir)
if err != nil {
return err
}
for _, entry := range entries {
// filepath.Join 用于拼接路径,会根据不同的操作系统,拼接符合操作系统的路径
filePath := filepath.Join(dir, entry.Name())
if entry.IsDir() {
// 如果是文件夹,则递归读取
if err := readDirRecursively(filePath); err != nil {
return err
}
// 判断读取的文件是不是以 .go 结尾
} else if filepath.Ext(filePath) == ".go" {
fileBytes, err := os.ReadFile(filePath)
if err != nil {
return err
}
fmt.Println(string(fileBytes))
}
}
return nil
}
ReadDir 可以传入数字,如果传入的数字小于 0,则读取全部文件,如果传入的数字大于 0,则读取指定数量的文件:
ReadDir(-1)读取所有文件ReadDir(1)读取一个文件
递归读取文件的另一种方法是使用 filepath.WalkDir 方法,代码如下:
func walkDir(dir string) error {
return filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
if !d.IsDir() && filepath.Ext(d.Name()) == ".go" {
fileBytes, err := os.ReadFile(path)
if err != nil {
return err
}
fmt.Println(path, string(fileBytes))
}
return nil
})
}
linux 文件权限
-rwxr-xr-x
rwx 三个一组,代表文件的权限
- 第一组:文件所有者的权限
- 第二组:文件所在组的权限
- 第三组:其他用户的权限
修改权限
$ chmod a-x xxx # a 表示所有用户,- 表示去掉权限,这里的意思是去掉所有的执行权限
# 运行前
-rwxr-xr-x
# 运行后
-rw-r--r--
a表示所有用户-表示去掉权限+表示加上权限
rwx 也可以用数字表示
r表示4w表示2x表示1
所以:
rwx可以用7表示r-x可以用5表示rw-可以用6表示