1. IsAbs返回路徑是否是一個絕對路徑
使用示例:
isAbs := path.IsAbs("/root/temp")
fmt.Println(isAbs)
源碼:
func IsAbs(path string) bool {
//路徑長度大於0 並且 第一個字符是 /
return len(path) > 0 && path[0] == '/'
}
2. Split函數將路徑從最後一個斜槓後面位置分隔爲兩個部分(dir和file)並返回。如果路徑中沒有斜槓,函數返回值dir會設爲空字符串,file會設爲path。兩個返回值滿足path == dir+file。
使用示例:
dir, file := path.Split("/root/temp/a.tar.gz")
fmt.Println(dir, file)
源碼:
func Split(path string) (dir, file string) {
//找到 / 最後一次出現的位置
i := strings.LastIndex(path, "/")
//切割字符串
return path[:i+1], path[i+1:]
}
3.Join函數可以將任意數量的路徑元素放入一個單一路徑裏,會根據需要添加斜槓。結果是經過簡化的,所有的空字符串元素會被忽略。
使用示例:
filePath := path.Join("/root","/temp","z.tar.gz")
fmt.Println(filePath)
源碼:
func Join(elem ...string) string {
//遍歷元素
for i, e := range elem {
if e != "" {
//找到第一個不是空的
//去掉空的字符串部分, 以/拼接字符串, clean處理
return Clean(strings.Join(elem[i:], "/"))
}
}
return ""
}
4. Dir返回路徑除去最後一個路徑元素的部分,即該路徑最後一個元素所在的目錄。在使用Split去掉最後一個元素後,會簡化路徑並去掉末尾的斜槓。如果路徑是空字符串,會返回".";如果路徑由1到多個斜槓後跟0到多個非斜槓字符組成,會返回"/";其他任何情況下都不會返回以斜槓結尾的路徑。
使用示例:
dir := path.Dir("/root/dir/a.tar.gz")
fmt.Println(dir)
源碼:
func Dir(path string) string {
//直接返回 split 目錄部分
dir, _ := Split(path)
return Clean(dir)
}
5.Base函數返回路徑的最後一個元素。在提取元素前會求掉末尾的斜槓。如果路徑是"",會返回".";如果路徑是隻有一個斜杆構成,會返回"/"。
使用示例:
dir := path.Base("/root/dir/a.tar.gz")
fmt.Println(dir)
源碼:
func Base(path string) string {
if path == "" {
//如果傳入的是空,返回 點
return "."
}
// Strip trailing slashes.
//path 長度不是0 並且 最後一個字符是 /
for len(path) > 0 && path[len(path)-1] == '/' {
//提取 不是 / 那部分 /root/a/ => /root/a
path = path[0 : len(path)-1]
}
// Find the last element
//找到 / 最後出現的位置 並且傳入的path有 /
if i := strings.LastIndex(path, "/"); i >= 0 {
//提取/ 後那部分 /root/a => a
path = path[i+1:]
}
// If empty now, it had only slashes.
//如果是空
if path == "" {
//就返回 /
return "/"
}
return path
}
6. Ext函數返回path文件擴展名。返回值是路徑最後一個斜槓分隔出的路徑元素的最後一個'.'起始的後綴(包括'.')。如果該元素沒有'.'會返回空字符串。
示例:
ext := path.Ext("/root/a.tar.gz")
fmt.Println(ext)
源碼:
func Ext(path string) string {
//循環 從後向前 path[i] 不能是/
for i := len(path) - 1; i >= 0 && path[i] != '/'; i-- {
if path[i] == '.' {
//如果碰到 . 返回 path .後的部分
return path[i:]
}
}
return ""
}
7.Clean函數通過單純的詞法操作返回和path代表同一地址的最短路徑。
示例:
realPath := path.Clean("/root/../etc")
fmt.Println(realPath)
源碼:
func Clean(path string) string {
//如果是空 返回 .
if path == "" {
return "."
}
//判斷第一個字符是否是 /
rooted := path[0] == '/'
n := len(path)
// Invariants:
// reading from path; r is index of next byte to process.
// writing to buf; w is index of next byte to write.
// dotdot is index in buf where .. must stop, either because
// it is the leading slash or it is a leading ../../.. prefix.
//字符存到 lazybuf結構體 字符串
out := lazybuf{s: path}
r, dotdot := 0, 0
if rooted {
out.append('/')
r, dotdot = 1, 1
}
//遍歷path 字符串每個字符
for r < n {
switch {
//字符是 / 不做特殊處理
case path[r] == '/':
// empty path element
r++
//字符是 . 並且 (是最後一個元素 或者 下一個字符是 / ) ./
case path[r] == '.' && (r+1 == n || path[r+1] == '/'):
// . element
r++
// ../ 這種情況 或者 最後是 .. eg: /root/.. 就要刪除上一個路徑的節點
case path[r] == '.' && path[r+1] == '.' && (r+2 == n || path[r+2] == '/'):
// .. element: remove to last /
//跳過 ..
r += 2
switch {
// out buf 索引位置 w 大於 點點 位置
case out.w > dotdot:
//可以刪除上一個元素
// can backtrack
out.w--
for out.w > dotdot && out.index(out.w) != '/' {
//刪除上一個元素, 結束是 不是 / /root/../ => /
out.w--
}
case !rooted:
//不是絕對路徑 eg: root/temp
// cannot backtrack, but not rooted, so append .. element.
if out.w > 0 {
out.append('/')
}
out.append('.')
out.append('.')
dotdot = out.w
}
default:
// real path element.
// add slash if needed
//是真正路徑節點 如 root
//向buf數組中先添加 /
if rooted && out.w != 1 || !rooted && out.w != 0 {
out.append('/')
}
// copy element
//循環 向buf中追加 下個 /前的 路徑的字符
//eg: root/ root追加到buf字節數組中
for ; r < n && path[r] != '/'; r++ {
out.append(path[r])
}
}
}
// Turn empty string into "."
if out.w == 0 {
return "."
}
//字符數組轉化成字符串返回, 因爲頻繁拼接字符串 耗性能 類似 java中stringbuf 的設計
return out.string()
}