您的位置 首页 golang

path/filepath—兼容操作系统的文件路径操作

path/filepath 包涉及到路径操作时,路径分隔符使用 os.PathSeparator 。不同系统,路径表示方式有所不同,比如 Unix 和 Windows 差别很大。本包能够处理所有的文件路径,不管是什么系统。

转自:go语言中文文档:www.topgoer.cn

注意,路径操作函数并不会校验路径是否真实存在。

解析路径名字符串

Dir() Base() 函数将一个路径名字符串分解成目录和文件名两部分。(注意一般情况,这些函数与 Unix 中 dirname 和 basename 命令类似,但如果路径以 / 结尾, Dir 的行为和 dirname 不太一致。)

 func Dir(path string) string
func Base(path string) string  

Dir 返回路径中除去最后一个路径元素的部分,即该路径最后一个元素所在的目录。在使用 Split 去掉最后一个元素后,会简化路径并去掉末尾的斜杠。如果路径是空字符串,会返回 “.”;如果路径由 1 到多个斜杠后跟 0 到多个非斜杠字符组成,会返回 “/“;其他任何情况下都不会返回以斜杠结尾的路径。

Base 函数返回路径的最后一个元素。在提取元素前会去掉末尾的斜杠。如果路径是 “”,会返回 “.”;如果路径是只有一个斜杆构成的,会返回 “/“。

比如,给定路径名 /home/polaris/studygolang.go Dir 返回 /home/polaris ,而 Base 返回 studygolang.go

如果给定路径名 /home/polaris/studygolang/ Dir 返回 /home/polaris/studygolang (这与 Unix 中的 dirname 不一致,dirname 会返回 /home/polaris),而 Base 返回 studygolang

有人提出此问题,见issue13199,不过官方认为这不是问题,如果需要和 dirname 一样的功能,应该自己处理,比如在调用 Dir 之前,先将末尾的 / 去掉。

此外, Ext 可以获得路径中文件名的扩展名。

func Ext(path string) string

Ext 函数返回 path 文件扩展名。扩展名是路径中最后一个从 . 开始的部分,包括 . 。如果该元素没有 . 会返回空字符串。

相对路径和绝对路径

某个进程都会有当前工作目录(进程相关章节会详细介绍),一般的相对路径,就是针对进程当前工作目录而言的。当然,可以针对某个目录指定相对路径。

绝对路径,在 Unix 中,以 / 开始;在 Windows 下以某个盘符开始,比如 C:\Program Files

func IsAbs(path string) bool

IsAbs 返回路径是否是一个绝对路径。而

func Abs(path string) (string, error)

Abs 函数返回 path 代表的绝对路径,如果 path 不是绝对路径,会加入当前工作目录以使之成为绝对路径。因为硬链接的存在,不能保证返回的绝对路径是唯一指向该地址的绝对路径。在 os.Getwd 出错时, Abs 会返回该错误,一般不会出错,如果路径名长度超过系统限制,则会报错。

func Rel(basepath, targpath string) (string, error)

Rel 函数返回一个相对路径,将 basepath 和该路径用路径分隔符连起来的新路径在词法上等价于 targpath 。也就是说, Join(basepath, Rel(basepath, targpath)) 等价于 targpath 。如果成功执行,返回值总是相对于 basepath 的,即使 basepath targpath 没有共享的路径元素。如果两个参数一个是相对路径而另一个是绝对路径,或者 targpath 无法表示为相对于 basepath 的路径,将返回错误。

 fmt.Println(filepath.Rel("/home/polaris/studygolang", "/home/polaris/studygolang/src/logic/topic.go"))
fmt.Println(filepath.Rel("/home/polaris/studygolang", "/data/studygolang"))

// Output:
// src/logic/topic.go <nil>
// ../../../data/studygolang <nil>  

路径的切分和拼接

对于一个常规文件路径,我们可以通过 Split 函数得到它的目录路径和文件名:

func Split(path string) (dir, file string)

Split 函数根据最后一个路径分隔符将路径 path 分隔为目录和文件名两部分( dir file )。如果路径中没有路径分隔符,函数返回值 dir 为空字符串, file 等于 path ;反之,如果路径中最后一个字符是 / ,则 dir 等于 path file 为空字符串。返回值满足 path == dir+file dir 非空时,最后一个字符总是 /

 // dir == /home/polaris/,file == studygolang
filepath.Split("/home/polaris/studygolang")

// dir == /home/polaris/studygolang/,file == ""
filepath.Split("/home/polaris/studygolang/")

// dir == "",file == studygolang
filepath.Split("studygolang")  

相对路径到绝对路径的转变,需要经过路径的拼接。 Join 用于将多个路径拼接起来,会根据情况添加路径分隔符。

func Join(elem …string) string

Join 函数可以将任意数量的路径元素放入一个单一路径里,会根据需要添加路径分隔符。结果是经过 Clean 的,所有的空字符串元素会被忽略。对于拼接路径的需求,我们应该总是使用 Join 函数来处理。

有时,我们需要分割 PATH GOPATH 之类的环境变量(这些路径被特定于 OS 的列表分隔符连接起来), filepath.SplitList 就是这个用途:

func SplitList(path string) []string

注意,与 strings.Split 函数的不同之处是:对 “”,SplitList 返回[]string{},而 strings.Split 返回 []string{“”}。 SplitList 内部调用的是 strings.Split

规整化路径

func Clean(path string) string

Clean 函数通过单纯的词法操作返回和 path 代表同一地址的最短路径。

它会不断的依次应用如下的规则,直到不能再进行任何处理:

  1. 将连续的多个路径分隔符替换为单个路径分隔符
  2. 剔除每一个 . 路径名元素(代表当前目录)
  3. 剔除每一个路径内的 .. 路径名元素(代表父目录)和它前面的非 .. 路径名元素
  4. 剔除开始于根路径的 .. 路径名元素,即将路径开始处的 /.. 替换为 / (假设路径分隔符是 /

返回的路径只有其代表一个根地址时才以路径分隔符结尾,如 Unix 的 / 或 Windows 的 C:\

如果处理的结果是空字符串,Clean 会返回 . ,代表当前路径。

符号链接指向的路径名

在上一节 os 包中介绍了 Readlink ,可以读取符号链接指向的路径名。不过,如果原路径中又包含符号链接, Readlink 却不会解析出来。 filepath.EvalSymlinks 会将所有路径的符号链接都解析出来。除此之外,它返回的路径,是直接可访问的。

func EvalSymlinks(path string) (string, error)

如果 path 或返回值是相对路径,则是相对于进程当前工作目录。

os.Readlink filepath.EvalSymlinks 区别示例程序:

 // 在当前目录下创建一个 studygolang.txt 文件和一个 symlink 目录,在 symlink 目录下对 studygolang.txt 建一个符号链接 studygolang.txt.2
fmt.Println(filepath.EvalSymlinks("symlink/studygolang.txt.2"))
fmt.Println(os.Readlink("symlink/studygolang.txt.2"))

// Ouput:
// studygolang.txt <nil>
// ../studygolang.txt <nil>  

文件路径匹配

func Match(pattern, name string) (matched bool, err error)

Match 指示 name 是否和 shell 的文件模式匹配。模式语法如下:

 pattern:
    { term }
term:
    '*'         匹配 0 或多个非路径分隔符的字符
    '?'         匹配 1 个非路径分隔符的字符
    '[' [ '^' ] { character-range } ']'  
                  字符组(必须非空)
    c           匹配字符 c(c != '*', '?', '\\', '[')
    '\\' c      匹配字符 c
character-range:
    c           匹配字符 c(c != '\\', '-', ']')
    '\\' c      匹配字符 c
    lo '-' hi   匹配区间[lo, hi]内的字符  

匹配要求 pattern 必须和 name 全匹配上,不只是子串。在 Windows 下转义字符被禁用。

Match 函数很少使用,搜索了一遍,标准库没有用到这个函数。而 Glob 函数在模板标准库中被用到了。

func Glob(pattern string) (matches []string, err error)

Glob 函数返回所有匹配了 模式字符串 pattern 的文件列表或者 nil(如果没有匹配的文件)。 pattern 的语法和 Match 函数相同。 pattern 可以描述多层的名字,如 /usr/*/bin/ed (假设路径分隔符是 / )。

注意, Glob 会忽略任何文件系统相关的错误,如读目录引发的 I/O 错误。唯一的错误和 Match 一样,在 pattern 不合法时,返回 filepath.ErrBadPattern 。返回的结果是根据文件名字典顺序进行了排序的。

Glob 的常见用法,是读取某个目录下所有的文件,比如写单元测试时,读取 testdata 目录下所有测试数据:

filepath.Glob(“testdata/*.input”)

遍历目录

在介绍 os 时,讲解了读取目录的方法,并给出了一个遍历目录的示例。在 filepath 中,提供了 Walk 函数,用于遍历目录树。

func Walk(root string, walkFn WalkFunc) error

Walk 函数会遍历 root 指定的目录下的文件树,对每一个该文件树中的目录和文件都会调用 walkFn ,包括 root 自身。所有访问文件 / 目录时遇到的错误都会传递给 walkFn 过滤。文件是按字典顺序遍历的,这让输出更漂亮,但也导致处理非常大的目录时效率会降低。 Walk 函数不会遍历文件树中的符号链接(快捷方式)文件包含的路径。

walkFn 的类型 WalkFunc 的定义如下:

type WalkFunc func(path string, info os.FileInfo, err error) error

Walk 函数对每一个文件 / 目录都会调用 WalkFunc 函数类型值。调用时 path 参数会包含 Walk root 参数作为前缀;就是说,如果 Walk 函数的 root 为 “dir”,该目录下有文件 “a”,将会使用 “dir/a” 作为调用 walkFn 的参数。 walkFn 参数被调用时的 info 参数是 path 指定的地址(文件 / 目录)的文件信息,类型为 os.FileInfo

如果遍历 path 指定的文件或目录时出现了问题,传入的参数 err 会描述该问题, WalkFunc 类型函数可以决定如何去处理该错误( Walk 函数将不会深入该目录);如果该函数返回一个错误, Walk 函数的执行会中止;只有一个例外,如果 Walk walkFn 返回值是 SkipDir ,将会跳过该目录的内容而 Walk 函数照常执行处理下一个文件。

os 遍历目录树的示例对应,使用 Walk 遍历目录树的示例程序在 walk,程序简单很多。

Windows 起作用的函数

filepath 中有三个函数: VolumeName FromSlash ToSlash ,针对非 Unix 平台的。

关于 path 包

path 包提供了对 / 分隔的路径的实用操作函数。

在 Unix 中,路径的分隔符是 / ,但 Windows 是 \ 。在使用 path 包时,应该总是使用 / ,不论什么系统。

path 包中提供的函数, filepath 都有提供,功能类似,但实现不同。

一般应该总是使用 filepath 包,而不是 path 包。

文章来源:智云一二三科技

文章标题:path/filepath—兼容操作系统的文件路径操作

文章地址:https://www.zhihuclub.com/86722.shtml

关于作者: 智云科技

热门文章

网站地图