1. 路径介绍
存储设备保存着数据,但是得有一种方便的模式让用户可以定位资源位置,操作系统采用一种路径字符 串的表达方式,这是一棵倒置的层级目录树,从根开始。
- 相对路径:不是以根目录开始的路径,例如 a/b 、 a/b/c 、 . 、 ../a/b 、 ./a/b/c
- 绝对路径:以斜杆开始的路径,例如 /a/b 、 /a/b/c 、 /t/../a/b ,window需要盘符 e:\a\b\c
- 路径分隔符:windows为 \ ,但是也支持 / ;Linux系统等为 /
2. 路径处理包
为了方便处理,Go语言标准库提供path包和更加方便的path/filepath包,使用filepath即可。
3. 路径拼接(filepath.Join)
作用:
由于路径是字符串,直接使用字符串拼接就可以了,也可以使用filepath.Join方法。
推荐使用filepath.Join,这个函数会将多个字符串参数组合成一个路径,并且会根据操作系统的要求,自动插入正确的路径分隔符。
语法:func filepath.Join(elem ...string) string
参数:
elem ...string:相对路径或者绝对路径。
返回值:
string:合并后的完整路径。
package main
import (
"fmt"
"path/filepath"
)
func main() {
p1 := "/a/b" + "/" + "c/d" + "/" + "f"
// 就算写错了分隔符,filepath.Join也会自动处理为正确的
p2 := filepath.Join("a/b", "c/d", "f") // 相对路径
p3 := filepath.Join("/a", "b", "c") // 绝对路径
fmt.Println(p1)
fmt.Println(p2)
}
=============调试结果=============
/a/b/c/d/f
a\b\c\d\f
\a\b\c
4. 路径分解
就是提取完整路径中的某一部分。
4.1 提取目录(filepath.Dir)
作用:
filepath.Dir
函数用于从完整的文件路径中提取目录部分。这个函数会返回给定路径中,文件名之前的目录路径。
语法:func filepath.Dir(path string) string
参数:
表示完整的文件路径。
返回值:
string:成功提取的目录部分。
package main
import (
"fmt"
"path/filepath"
)
func main() {
// 注意a前面没有/,所以是个相对路径
fmt.Println("======filepath.Join======")
p1 := filepath.Join("a/b", "c/d", "f", "mysql.ini")
fmt.Printf("p1的类型=%T\np1的值=%+[1]v\n", p1)
fmt.Println("======filepath.Dir======")
dir := filepath.Dir(p1) // 提取目录
fmt.Printf("dir=%s\n", dir)
}
======filepath.Join======
p1的类型=string
p1的值=a\b\c\d\f\mysql.ini
======filepath.Dir======
dir=a\b\c\d\f
4.2 提取文件扩展名(filepath.Ext)
作用:
Ext返回path使用的文件扩展名。扩展是path的最后一个元素的最后一个点开始的后缀;如果没有点,则为空。
语法:func filepath.Ext(path string) string
参数:
path string:文件路径变量。
返回值:
string:返回截取到的文件扩展名。
package main
import (
"fmt"
"path/filepath"
)
func main() {
// 注意a前面没有/,所以是个相对路径
fmt.Println("======filepath.Join======")
p1 := filepath.Join("a/b", "c/d", "f", "mysql.ini")
fmt.Printf("p1的类型=%T\np1的值=%+[1]v\n", p1)
fmt.Println("======filepath.Ext======")
dir := filepath.Ext(p1)
fmt.Printf("dir=%s", dir)
}
======filepath.Join======
p1的类型=string
p1的值=a\b\c\d\f\mysql.ini
======filepath.Ext======
dir=.ini
4.3 提取文件名(filepath.Base)
作用:
filepath.Base
函数用于从完整的文件路径中提取文件名部分。这个函数会返回给定路径中的最后一个元素,即文件名或目录名。
语法:func filepath.Base(path string) string
参数:
path string:完整的文件路径。
返回值:
string:表示从给定路径中提取的最后一个元素,即文件名或目录名。
import (
"fmt"
"path/filepath"
)
func main() {
// 提取文件名
base := filepath.Base("path/to/the/file.txt")
fmt.Println(base) // 输出: file.txt
// 处理绝对路径
baseAbsolute := filepath.Base("/home/user/file.txt")
fmt.Println(baseAbsolute) // 输出: file.txt
// 处理只有目录没有文件名的路径
baseDir := filepath.Base("path/to/")
fmt.Println(baseDir) // 输出: (空字符串,因为路径以斜杠结尾)
// 处理根目录
baseRoot := filepath.Base("/home")
fmt.Println(baseRoot) // 输出: home
// 处理没有目录的文件名
baseNoDir := filepath.Base("file.txt")
fmt.Println(baseNoDir) // 输出: file.txt
// 处理隐藏文件
baseHidden := filepath.Base(".hiddenfile")
fmt.Println(baseHidden) // 输出: .hiddenfile
}
5. 目录
5.1 获取当前工作目录(os.Getwd)
作用:
Getwd返回与当前目录对应的根路径名(注意是程序的运行目录)。如果当前目录可以通过多个路径到达(由于符号链接),Getwd可能返回其中的任何一个。
语法:func os.Getwd() (dir string, err error)
返回值:
dir string:表示当前工作目录的路径。
err error:如果发生错误,返回错误对象;否则返回
nil
。
package main
import (
"fmt"
"os"
)
func main() {
dir, err := os.Getwd()
if err != nil {
panic(err)
} else {
fmt.Printf("当前工作目录=%s", dir)
}
}
=======调试结果=======
当前工作目录=d:\个人\GO开发\20240624
5.2 获取当前登录用户的家目录(os.UserHomeDir)
作用:
os.UserHomeDir
函数用于获取当前用户的主目录路径。
os.UserHomeDir
在不同的操作系统上都能正常工作,它会根据操作系统的环境变量(如HOME
在 Unix 系统上,USERPROFILE
或HOMEPATH
在 Windows 系统上)来确定用户的主目录。
语法:
func UserHomeDir() (string, error)
返回值:
string:表示当前用户的主目录路径。
error:如果发生错误,返回错误对象;否则返回
nil
。
package main
import (
"fmt"
"os"
)
func main() {
s, err := os.UserHomeDir()
if err != nil {
panic(err)
} else {
fmt.Printf("当前登录用户家目录=%s", s)
}
}
=======调试结果=======
当前登录用户家目录=C:\Users\123456
6. 绝对路径
6.1 判断绝对路径(filepath.IsAbs)
作用:
filepath.IsAbs
函数用于检查给定的路径是否是绝对路径。
语法:func filepath.IsAbs(path string) (b bool)
参数:
path string: 表示要检查的文件路径。
返回值:
b bool:如果路径是绝对路径,则返回
true
;否则返回false
。
package main
import (
"fmt"
"path/filepath"
)
func main() {
p1 := filepath.Join("a/b", "c/d", "f", "mysql.ini")
fmt.Printf("p1的路径=%s\n", p1)
path := filepath.IsAbs(p1)
fmt.Printf("p1是否为绝对路径=%v", path)
}
=====调试结果=====
p1的路径=a\b\c\d\f\mysql.ini
p1是否为绝对路径=false
6.2 将相对路径转换为绝对路径(filepath.Abs)
作用:
filepath.Abs
函数用于将相对路径转换为绝对路径。它根据当前工作目录(程序运行目录)和提供的相对路径来计算绝对路径。
语法:func filepath.Abs(path string) (string, error)
参数:
path string:表示要转换的相对文件路径。
返回值:
string
:表示转换后的绝对路径。
error
:如果发生错误,返回错误对象;否则返回nil
。
package main
import (
"fmt"
"path/filepath"
)
func main() {
p1 := filepath.Join("a/b", "c/d", "f", "mysql.ini")
fmt.Printf("p1的路径=%s\n", p1)
abs, err := filepath.Abs(p1)
if err != nil {
panic(err)
} else {
fmt.Printf("Abs处理后的绝对路径=%s", abs)
}
}
=====调试结果=====
p1的路径=a\b\c\d\f\mysql.ini
Abs处理后的绝对路径=d:\个人\GO开发\20240624\a\b\c\d\f\mysql.ini
7. 存在性检测
7.1 获取文件或目录信息(os.Stat)
作用:
os.Stat
函数用于获取文件或目录的状态信息。这个函数是os
包的一部分,它返回一个fs.FileInfo
接口,该接口提供了文件的大小、修改时间、权限等信息。
语法:func os.Stat(name string) (fs.FileInfo, error)
参数:
name string:表示要获取状态信息的文件或目录的路径。
返回值:
fs.FileInfo:一个实现了
FileInfo
接口的对象,包含了文件或目录的详细信息。error:如果发生错误,返回错误对象;否则返回
nil
。
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
p1 := filepath.Join("a/b", "c/d", "f", "mysql.ini")
fmt.Printf("p1的路径=%s\n", p1)
fi, err := os.Stat(p1)
if err != nil {
fmt.Println("获取文件信息异常:", err)
} else {
fmt.Println(fi)
}
}
=====调试结果=====
p1的路径=a\b\c\d\f\mysql.ini
获取文件信息异常: CreateFile a\b\c\d\f\mysql.ini: The system cannot find the path specified.
7.2 检测文件或目录是否存在
7.2.1 os.IsNotExist
作用:
os.IsNotExist
函数用于检查一个错误是否表示文件或目录不存在的错误。
语法:func os.IsNotExist(err error) bool
参数:
err error:表示要检查的错误对象。
返回值:
bool:如果错误表示文件已存在,则返回
true
;否则返回false
。
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
fmt.Println("==========调试结果==========")
p1 := filepath.Join("a/b", "c/d", "f", "mysql.ini")
fmt.Printf("p1的路径=%s\n", p1)
fi, err := os.Stat(p1)
if err != nil {
fmt.Printf("获取文件信息异常:%s\n文件不存在:%v\n", err, os.IsNotExist(err))
} else {
fmt.Println(fi)
}
}
==========调试结果==========
p1的路径=a\b\c\d\f\mysql.ini
获取文件信息异常:CreateFile a\b\c\d\f\mysql.ini: The system cannot find the path specified.
文件不存在:true
8. 创建目录和文件
8.1 创建目录
创建目录主要有这3个函数:
- os.Mkdir
创建一个新的子目录,父目录必须存在,否则报错。- os.MkdirAll
递归创建一个目录路径。- os.MkdirTemp
创建一个临时目录。
8.1.1 os.MkdirAll
作用:
os.MkdirAll
函数是 Go 语言标准库os
包中的一个函数,用于递归创建一个目录路径,包括任何必要的中间目录。这个函数非常适合在需要确保整个目录结构都存在时使用,例如在创建文件之前。创建时,如果用的是相对路径,则会在程序所在目录下创建。
目录已存在,创建也不会报错。
语法:func os.MkdirAll(path string, perm fs.FileMode) error
参数:
path string:要创建的目录路径,可以包含多级目录。
perm fs.FileMode:设置目录的权限。fs.FileMode 是一个类型,通常使用常量如 fs.ModePerm来表示权限,也可以手动指定权限如0755
返回值:
error:如果所有目录都成功创建,则返回 nil;如果发生错误(例如,权限不足),则返回错误对象。
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("==========调试结果==========")
err := os.MkdirAll("d:/个人/学习/Go/文件与目录操作/创建测试", os.ModePerm) // os.ModePerm默认权限为511
// err := os.MkdirAll("创建测试", os.ModePerm)// 如果是相对路径,则会在程序所在目录下创建
if err != nil {
fmt.Println("目录创建失败:", err)
} else {
fmt.Println("递归创建目录成功!")
}
}
==========调试结果==========
递归创建目录成功!
8.2 创建文件
创建文件可以使用os包中的两个函数:
- os.Create
注意:如果文件已经存在了,该函数会先清空文件中原本的内容,再创建。- os.OpenFile
OpenFile能够更细粒度的去控制文件的权限。
8.2.1 os.Create
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("==========调试结果==========")
f, err := os.Create("d:/个人/学习/Go/文件与目录操作/创建测试/create-test.txt")
if err != nil {
panic(err)
}
fmt.Println("文件创建成功!")
defer f.Close()
}
==========调试结果==========
文件创建成功!
9. 获取文件或目录元数据信息(Stat)
除了利用stat来判断文件是否存在,还可以检测文件元数据,如判断是否为目录、是否为文件、文件权限、大小、修改时间等。
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("==========调试结果==========")
p1 := "d:/个人/学习/Go/文件与目录操作/创建测试/create-test.txt"
fi, err := os.Stat(p1)
if err != nil {
panic(err)
} else {
fmt.Printf("文件名=%s\n是否为目录=%v\n文件的权限=%v\n文件的大小=%d\n文件的修改时间=%s\n", fi.Name(), fi.IsDir(), fi.Mode(), fi.Size(), fi.ModTime())
}
}
==========调试结果==========
文件名=create-test.txt
是否为目录=false
文件的权限=-rw-rw-rw-
文件的大小=0
文件的修改时间=2024-09-04 15:44:45.291237 +0800 CST
10. 遍历目录
10.1 os.ReadDir(非递归遍历)
作用:
读取指定目录下的所有条目(包括文件和子目录),非递归。
语法:func os.ReadDir(name string) ([]fs.DirEntry, error)
参数:
name string:要读取的目录的路径。
返回值:
[]fs.DirEntry:一个包含
fs.DirEntry
接口的切片,每个条目代表目录中的一个文件或子目录。error:如果读取目录过程中发生错误,则返回错误对象;否则返回
nil
。
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("==========调试结果==========")
de, err := os.ReadDir("D:/个人/学习/Go/文件与目录操作")
if err != nil {
panic(err)
}
fmt.Println(de)
for i, v := range de {
fmt.Println(i, v, v.Name(), v.Type(), v.IsDir())
}
}
==========调试结果==========
[{0xc00010a000} {0xc00010a070}]
0 {0xc00010a000} test.txt ---------- false
1 {0xc00010a070} 创建测试 d--------- true
10.2 filepath.WalkDir(递归遍历)
作用:
用于递归遍历一个目录及其所有子目录中的文件和子目录。
语法:func filepath.WalkDir(root string, fn fs.WalkDirFunc) error
参数:
root string:要遍历的根目录的路径。
fn fs.WalkDirFunc:一个回调函数,用于处理每个文件和目录。它接收三个参数:当前遍历到的路径、一个
fs.DirEntry
对象(包含文件或目录的信息),以及在读取目录时可能发生的错误。返回值:
error:如果遍历过程中发生错误,则返回错误对象;否则返回
nil
。
package main
import (
"fmt"
"io/fs"
"path/filepath"
)
func main() {
fmt.Println("==========调试结果==========")
filepath.WalkDir(
"D:/个人/学习/Go/文件与目录操作",
func(path string, d fs.DirEntry, err error) error {
fmt.Println(path, d.Name(), d.IsDir())
return err
}) // path string,就是遍历过程中遍历到的文件或目录
}
==========调试结果==========
D:/个人/学习/Go/文件与目录操作 文件与目录操作 true
D:\个人\学习\Go\文件与目录操作\test.txt test.txt false
D:\个人\学习\Go\文件与目录操作\创建测试 创建测试 true
D:\个人\学习\Go\文件与目录操作\创建测试\create-test.txt create-test.txt false