path/filepath
軟件包filepath實現了實用程序例程,用於以與目標操作系統定義的文件路徑兼容的方式來處理文件名路徑。
文件路徑包使用正斜杠或反斜杠,具體取決於操作系統。若要處理諸如URL之類的路徑,無論使用什么操作系統,該路徑始終使用正斜杠,請參閱路徑包。
------------------------------------------------------------
路徑分隔符轉換:
const (
Separator = os.PathSeparator // 路徑分隔符(分隔路徑元素)
ListSeparator = os.PathListSeparator // 路徑列表分隔符(分隔多個路徑)
)
------------------------------------------------------------
Abs
// func Abs(path string) (string, error)
// 返回所給目錄的絕對路徑
package main
import (
"fmt"
"path/filepath"
)
func main() {
// 返回所給目錄的絕對路徑
s1, _ := filepath.Abs("./a/b")
fmt.Println(s1)
fmt.Println(filepath.Abs(s1)) // 不同系統顯示不一樣
s2 := "/root/a/b/c"
s3 := "a/b/v/"
fmt.Println(filepath.IsAbs(s1)) // true
fmt.Println(filepath.IsAbs(s2)) // true
fmt.Println(filepath.IsAbs(s3)) // false
}
/*
$ go run Abs.go
/Users/jordan/GolandProjects/LearnGoProject/go-new-course/day06-20200516/filepath/a/b
/Users/jordan/GolandProjects/LearnGoProject/go-new-course/day06-20200516/filepath/a/b <nil>
true
true
false
*/
IsAbs
// 判斷路徑是否為絕對路徑
// IsAbs(path string) bool
package main
import (
"fmt"
"path/filepath"
)
func main() {
fmt.Println("On Unix:")
fmt.Println("1: ", filepath.IsAbs("/home/gopher"))
fmt.Println("2: ", filepath.IsAbs(".bashrc"))
fmt.Println("3: ", filepath.IsAbs(".."))
fmt.Println("4: ", filepath.IsAbs("."))
fmt.Println("5: ", filepath.IsAbs("/"))
fmt.Println("6: ", filepath.IsAbs(""))
}
/*
$ go run IsAbs.go
On Unix:
1: true
2: false
3: false
4: false
5: true
6: false
*/
Base
// func Base(path string) string
// 獲取 path 中最后一個分隔符之后的部分(不包含分隔符)
// Split(path string) (dir, file string)
// 獲取 path 中最后一個分隔符前后的兩部分,之前包含分隔符,之后不包含分隔符
// Ext(path string) string
// 獲取路徑字符串中的文件擴展名
package main
import (
"fmt"
"path/filepath"
)
func main() {
fmt.Println("On Unix:")
fmt.Println(filepath.Base("/foo/bar/baz.js"))
fmt.Println(filepath.Base("/foo/bar/baz"))
fmt.Println(filepath.Base("/foo/bar/baz/"))
fmt.Println(filepath.Base("dev.txt"))
fmt.Println(filepath.Base("../todo.txt"))
fmt.Println(filepath.Base(".."))
fmt.Println(filepath.Base("."))
fmt.Println(filepath.Base("/"))
fmt.Println(filepath.Base(""))
}
/*
$ go run Base.go
On Unix:
baz.js
baz
baz
dev.txt
todo.txt
..
.
/
.
*/
Clean
// 清理路徑中的多余字符,比如 /// 或 ../ 或 ./
// Clean(path string) string
package main
import (
"fmt"
"path/filepath"
)
func main() {
// Linux為例
s := filepath.Clean("a/./b/:::/..// /c/..////d///")
fmt.Println("1: ", s)
//返回等價的最短路徑
//1.用一個斜線替換多個斜線
fmt.Println("2: ", filepath.Clean("/.../..../////abc/abc"))
//2.清除當前路徑.
fmt.Println("3: ", filepath.Clean("./1.txt"))
//3.清除內部的..和他前面的元素
fmt.Println("4: ", filepath.Clean("C:/a/b/../c"))
//4.以/..開頭的,變成/
fmt.Println("5: ", filepath.Clean("/../1.txt"))
}
/*
$ go run Clean.go
1: a/b/ /d
2: /.../..../abc/abc
3: 1.txt
4: C:/a/c
5: /1.txt
*/
Dir
// Dir(path string) string
// 獲取 path 中最后一個分隔符之前的部分(不包含分隔符)
package main
import (
"fmt"
"path/filepath"
)
func main() {
fmt.Println("On Unix:")
fmt.Println(filepath.Dir("/foo/bar/baz.js"))
fmt.Println(filepath.Dir("/foo/bar/baz"))
fmt.Println(filepath.Dir("/foo/bar/baz/"))
fmt.Println(filepath.Dir("/dirty//path///"))
fmt.Println(filepath.Dir("dev.txt"))
fmt.Println(filepath.Dir("../todo.txt"))
fmt.Println(filepath.Dir(".."))
fmt.Println(filepath.Dir("."))
fmt.Println(filepath.Dir("/"))
fmt.Println(filepath.Dir(""))
}
/*
$ go run DIr.go
On Unix:
/foo/bar
/foo/bar
/foo/bar/baz
/dirty/path
.
..
.
.
/
.
*/
Ext
// Ext(path string) string
// 獲取路徑字符串中的文件擴展名
package main
import (
"fmt"
"path/filepath"
)
func main() {
fmt.Printf("No dots: %q\n", filepath.Ext("index"))
fmt.Printf("One dot: %q\n", filepath.Ext("index.js"))
fmt.Printf("Two dots: %q\n", filepath.Ext("main.test.js"))
}
/*
$ go run Ext.go
No dots: ""
One dot: ".js"
Two dots: ".js"
*/
FromSlash-ToSlash
// 下面兩個函數主要用於將 Windows 路徑分隔符轉換為 Linux 路徑分隔符,處理完后再轉換回去,只在 Windows 中有用,在 Linux 中沒必要:
// 將 path 中平台相關的路徑分隔符轉換為 '/'
// ToSlash(path string) string
// 將 path 中的 '/' 轉換為系統相關的路徑分隔符
// FromSlash(path string) string
package main
import (
"fmt"
"net/url"
"os"
"path/filepath"
)
func main() {
s := "http://www.site.com/a/b/c/d"
u, _ := url.Parse(s)
fmt.Println(u)
s = u.Path
fmt.Println(s)
// 下面這句用於 Windows 系統
s = filepath.FromSlash(s)
fmt.Println(s)
// 創建目錄試試
if err := os.MkdirAll(s[1:], 0777); err != nil {
fmt.Println(err)
}
// 下面這句用於 Windows 系統
s = filepath.ToSlash(s)
fmt.Println(s)
}
/*
$ go run FromSlash.go
http://www.site.com/a/b/c/d
/a/b/c/d
/a/b/c/d
/a/b/c/d
*/
Glob
// 列出與指定的模式 pattern 完全匹配的文件或目錄(匹配原則同match)
// Glob(pattern string) (matches []string, err error)
package main
import (
"fmt"
"path/filepath"
)
func main() {
// 列出 filepath 的子目錄中所包含的以 ba(忽略大小寫)開頭的項目
list, err := filepath.Glob("/Users/jordan/GolandProjects/LearnGoProject/go-new-course/day06-20200516/*/[Bb]*")
if err != nil {
fmt.Println(err)
}
for _, v := range list {
fmt.Println(v)
}
}
/*
$ go run Glob.go
/Users/jordan/GolandProjects/LearnGoProject/go-new-course/day06-20200516/a/b
/Users/jordan/GolandProjects/LearnGoProject/go-new-course/day06-20200516/filepath/Base.go
/Users/jordan/GolandProjects/LearnGoProject/go-new-course/day06-20200516/test/b.go
/Users/jordan/GolandProjects/LearnGoProject/go-new-course/day06-20200516/test/b.txt
*/
Join
// 將 elem 中的多個元素合並為一個路徑,忽略空元素,清理多余字符。
// Join(elem ...string) string
package main
import (
"fmt"
"path/filepath"
)
func main() {
fmt.Println("On Unix:")
fmt.Println("1: ", filepath.Join("a", "b", "c"))
fmt.Println("2: ", filepath.Join("a", "b/c"))
fmt.Println("3: ", filepath.Join("a/b", "c"))
fmt.Println("4: ", filepath.Join("a/b", "/c"))
}
/*
$ go run Join.go
On Unix:
1: a/b/c
2: a/b/c
3: a/b/c
4: a/b/c
*/
Match
// 判斷 name 是否和指定的模式 pattern 完全匹配
// Match(pattern, name string) (matched bool, err error)
// pattern 規則如下:
// 可以使用 ? 匹配單個任意字符(不匹配路徑分隔符)。
// 可以使用 * 匹配 0 個或多個任意字符(不匹配路徑分隔符)。
// 可以使用 [] 匹配范圍內的任意一個字符(可以包含路徑分隔符)。
// 可以使用 [^] 匹配范圍外的任意一個字符(無需包含路徑分隔符)。
// [] 之內可以使用 - 表示一個區間,比如 [a-z] 表示 a-z 之間的任意一個字符。
// 反斜線用來匹配實際的字符,比如 \* 匹配 *,\[ 匹配 [,\a 匹配 a 等等。
// [] 之內可以直接使用 [ * ?,但不能直接使用 ] -,需要用 \]、\- 進行轉義。
package main
import (
"fmt"
"path/filepath"
)
func main() {
fmt.Println("On Unix:")
fmt.Println(filepath.Match("/home/catch/*", "/home/catch/foo")) // true
fmt.Println(filepath.Match("/home/catch/*", "/home/catch/foo/bar")) // false
fmt.Println(filepath.Match("/home/?opher", "/home/gopher")) // true
fmt.Println(filepath.Match("/home/\\*", "/home/*")) // true
fmt.Println(filepath.Match(`???`, `abc`)) // true
fmt.Println(filepath.Match(`???`, `abcd`)) // false
fmt.Println(filepath.Match(`*`, `abc`)) // true
fmt.Println(filepath.Match(`*`, ``)) // true
fmt.Println(filepath.Match(`a*`, `abc`)) // true
fmt.Println(filepath.Match(`???\\???`, `abc\def`)) // true
fmt.Println(filepath.Match(`???/???`, `abc/def`)) // true
fmt.Println(filepath.Match(`/*/*/*/`, `/a/b/c/`)) // true
fmt.Println(filepath.Match(`[aA][bB][cC]`, `aBc`)) // true
fmt.Println(filepath.Match(`[^aA]*`, `abc`)) // false
fmt.Println(filepath.Match(`[a-z]*`, `a+b`)) // true
fmt.Println(filepath.Match(`\[*\]`, `[a+b]`)) // true
fmt.Println(filepath.Match(`[[\]]*[[\]]`, `[]`)) // true
}
Rel
// 獲取 targpath 相對於 basepath 的路徑。
// 要求 targpath 和 basepath 必須“都是相對路徑”或“都是絕對路徑”。
// Rel(basepath, targpath string) (string, error)
package main
import (
"fmt"
"path/filepath"
)
func main() {
//例1:
paths := []string{
"/a/b/c",
"/b/c",
"./b/c",
}
base := "/a"
fmt.Println("On Unix:")
for _, p := range paths {
rel, err := filepath.Rel(base, p)
fmt.Printf("%q: %q %v\n", p, rel, err)
}
/*
On Unix:
"/a/b/c": "b/c" <nil>
"/b/c": "../b/c" <nil>
"./b/c": "" Rel: can't make ./b/c relative to /a
*/
//例2:
// 都是絕對路徑
s, err := filepath.Rel(`/a/b/c`, `/a/b/c/d/e`)
fmt.Println(s, err) // d/e <nil>
// 都是相對路徑
s, err = filepath.Rel(`a/b/c`, `a/b/c/d/e`)
fmt.Println(s, err) // d/e <nil>
// 一個絕對一個相對
s, err = filepath.Rel(`/a/b/c`, `a/b/c/d/e`)
fmt.Println(s, err)
// Rel: can't make a/b/c/d/e relative to /a/b/c
// 一個相對一個絕對
s, err = filepath.Rel(`a/b/c`, `/a/b/c/d/e`)
fmt.Println(s, err)
// Rel: can't make /a/b/c/d/e relative to a/b/c
// 從 `a/b/c` 進入 `a/b/d/e`,只需要進入 `../d/e` 即可
s, err = filepath.Rel(`a/b/c`, `a/b/d/e`)
fmt.Println(s, err) // ../d/e <nil>
}
Split
// 獲取 path 中最后一個分隔符前后的兩部分
// 之前包含分隔符,之后不包含分隔符
// Split(path string) (dir, file string)
package main
import (
"fmt"
"path/filepath"
)
func main() {
paths := []string{
"/home/arnie/amelia.jpg",
"/mnt/photos/",
"rabbit.jgp",
"/usr/local//go",
}
fmt.Println("On Unix:")
for _, path := range paths {
dir, file := filepath.Split(path)
fmt.Printf("input: %q\n\tdir: %q\n\tfile: %q\n", path, dir, file)
}
}
/*
$ go run Split.go
On Unix:
input: "/home/arnie/amelia.jpg"
dir: "/home/arnie/"
file: "amelia.jpg"
input: "/mnt/photos/"
dir: "/mnt/photos/"
file: ""
input: "rabbit.jgp"
dir: ""
file: "rabbit.jgp"
input: "/usr/local//go"
dir: "/usr/local//"
file: "go"
*/
SplitList
// 將路徑序列 操作系統特別的連接符組成的path,通常用在PATH或者GOPARTH環境變量中, 分割為多條獨立的路徑。跟strings.Split不同,當傳入空的字符串,SplitList會返回一個空的切片
// SplitList(path string) []string
package main
import (
"fmt"
"path/filepath"
)
func main() {
fmt.Println("On Unix:", filepath.SplitList("/a/b/c:/usr/bin"))
fmt.Println("On Unix:", filepath.SplitList(""))
}
/*
$ go run SplitList.go
On Unix: [/a/b/c /usr/bin]
On Unix: []
*/
Walk-WalkFunc
// 遍歷指定目錄(包括子目錄),對遍歷到的項目用 walkFn 函數進行處理。
// Walk遍歷以root為根的文件樹,為樹中的每個文件或目錄(包括root)調用walkFn。
// walkFn會過濾訪問文件和目錄時出現的所有錯誤。這些文件以詞法順序進行遍歷,這使輸出具有確定性,但是這意味着對於非常大的目錄,遍歷可能效率不高。walk不能找到鏈接的文件
// Walk(root string, walkFn WalkFunc) error
// 文件處理函數定義如下,如果 WalkFunc 返回 nil,則 Walk 函數繼續遍歷,如果返回 SkipDir,則 Walk 函數會跳過當前目錄(如果當前遍歷到的是文件,則同時跳過后續文件及子目錄),繼續遍歷下一個目錄。
// 如果返回其它錯誤,則 Walk 函數會中止遍歷過程。
// 在 Walk 遍歷過程中,如果遇到錯誤,則會將錯誤通過 err 傳遞給WalkFunc 函數,同時 Walk 會跳過出錯的項目,繼續處理后續項目。
//type WalkFunc func(path string, info os.FileInfo, err error) error
package main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
)
func prepareTestDirTree(tree string) (string, error) {
tmpDir, err := ioutil.TempDir("", "")
if err != nil {
return "", fmt.Errorf("error creating temp directory: %v\n", err)
}
err = os.MkdirAll(filepath.Join(tmpDir, tree), 0755)
if err != nil {
os.RemoveAll(tmpDir)
return "", err
}
return tmpDir, nil
}
func main() {
tmpDir, err := prepareTestDirTree("dir/to/walk/skip")
if err != nil {
fmt.Printf("unable to create test dir tree: %v\n", err)
return
}
defer os.RemoveAll(tmpDir)
os.Chdir(tmpDir)
subDirToSkip := "skip"
fmt.Println("On Unix: ")
err = filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Printf("prevent panic by handing failure accessing a path %q: %v\n", path, err)
return err
}
if info.IsDir() && info.Name() == subDirToSkip {
fmt.Printf("skipping a dir without errors: %+v \n", info.Name())
return filepath.SkipDir
}
fmt.Printf("visited file or dir:%q\n", path)
return nil
})
if err != nil {
fmt.Printf("error walking the path %q: %v\n", tmpDir, err)
return
}
}
/*
$ go run Walk.go
On Unix:
visited file or dir:"."
visited file or dir:"dir"
visited file or dir:"dir/to"
visited file or dir:"dir/to/walk"
skipping a dir without errors: skip
*/