golang源碼閱讀-path

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()
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章