zoukankan      html  css  js  c++  java
  • filepath:处理文件路径的一把好手

    1.ToSlash(path string) string

    将相关平台的路径分隔符转为/

    package main
    
    import (
    	"fmt"
    	"os"
    	"path/filepath"
    )
    
    func main() {
    	sep := os.PathSeparator
    
    	// 查看当前平台的系统路径分隔符,windows平台是
    	fmt.Println(string(sep))  // 
    
    	// 将分割符转为/
    	fmt.Println(filepath.ToSlash(`C:python37python.exe`))  // C:/python37/python.exe
    
    	// 注意:该函数不在意路径是否存在,只是当成普通的字符串进行处理
    	// 比如我输入一个不存在的路径也是可以的
    	fmt.Println(filepath.ToSlash(`C:python37python.exepython.exe`))  // C:/python37/python.exe/python.exe
    }
    

    2.FromSlash(path string) string

    和ToSlash相反,是将/转化为相关系统的路径分隔符

    package main
    
    import (
    	"fmt"
    	"path/filepath"
    )
    
    func main() {
    	fmt.Println(filepath.FromSlash(`C:/python37/python.exe`))  // C:python37python.exe
    	fmt.Println(filepath.FromSlash(`C:python37/python.exe`))  // C:python37python.exe
    	fmt.Println(filepath.FromSlash(`C:python37python.exe////`))  // C:python37python.exe\\
    
    	/*
    	可以看到,这两个函数只是简单的字符串替换罢了,在源码里面也是这么做的
    	func FromSlash(path string) string {
    		if Separator == '/' {
    			return path
    		}
    		return strings.ReplaceAll(path, "/", string(Separator))
    	}
    	另外,这两个函数在linux下面也能用,但是没有意义,因为linux的路径分隔符就是/
    	 */
    }
    

    3.Dir(path string) string

    获取path中最后一个分割符前面的部分,类似于python中的os.path.dirname(path)

    package main
    
    import (
    	"fmt"
    	"path/filepath"
    )
    
    func main() {
    	path := `c:python37python.exe`
    	fmt.Println(filepath.Dir(path))  // c:python37
    }
    

    4.Base(path string) string

    获取path中最后一个分割符后面的部分,类似于python中的os.path.basename(path)

    package main
    
    import (
    	"fmt"
    	"path/filepath"
    )
    
    func main() {
    	path := `c:python37python.exe`
    	fmt.Println(filepath.Base(path))  // python.exe
    }
    

    5.Split(path string) (dir, file string)

    相当于是Dir和Base的组合,得到最后一个分割符的前面和后面两部分,类似于python中os.path.split

    package main
    
    import (
    	"fmt"
    	"path/filepath"
    )
    
    func main() {
    	path := `c:python37python.exe`
    	dir, file := filepath.Split(path)
    	fmt.Println(dir, file) // c:python37 python.exe
    }
    

    6.Ext(path string) string

    获取path中的文件扩展名,类似于python中的os.path.splitext(path)[1]

    package main
    
    import (
    	"fmt"
    	"path/filepath"
    )
    
    func main() {
    	path := `c:python37python.exe`
    	fmt.Println(filepath.Ext(path))  // .exe
    }
    

    7.Rel(basepath, targpath string) (string, error)

    获取targpath相对于basepath的路径,怎么理解呢?就是basepath进行什么样的操作,才能得到targpath。其中两者必须都是相对路径或者绝对路径

    package main
    
    import (
    	"fmt"
    	"path/filepath"
    )
    
    func main() {
    	path1 := `c:python37python.exe`
    	path2 := `c:python37`
    	p1, err1 := filepath.Rel(path1, path2)
    	if err1 != nil {
    		fmt.Println(err1)
    	}else{
    		fmt.Println(p1)  // ..
    	}
    	//得到的结果是..,表示path1组合..就能得到path2
    
    	
    	path1 = `c:python37`
    	path2 = `c:python37python.exe`
    	p2, err2 := filepath.Rel(path1, path2)
    	if err2 != nil {
    		fmt.Println(err2)
    	}else{
    		fmt.Println(p2)  // python.exe
    	}
    	// 表示path1再组合python.exe就能得到path2
    
    	
    	path1 = `c:python37`
    	path2 = `c:go`
    	p3, err3 := filepath.Rel(path1, path2)
    	if err3 != nil {
    		fmt.Println(err3)
    	}else{
    		fmt.Println(p3) // ..go
    	}
    	
    
    	path1 = `c:python37`
    	path2 = `d:overwatch`
    	p4, err4 := filepath.Rel(path1, path2)
    	if err4 != nil {
    		fmt.Println(err4) // Rel: can't make d:overwatch relative to c:python37
    	}else {
    		fmt.Println(p4)
    	}
    	//在window上,如果跨越了盘符,是没有办法的
    	
    }
    

    8.Join(elem ...string) string

    将多个路径进行组合

    package main
    
    import (
    	"fmt"
    	"path/filepath"
    )
    
    func main() {
    	path1 := `c:python37`
    	path2 := `lib`
    	path3 := `site-packages`
    	path4 := `tornado`
    	fmt.Println(filepath.Join(path1, path2, path3, path4))  // c:python37libsite-packages	ornado
    
    	fmt.Println(filepath.Join(path1, path2, "scripts", "pip"))  // c:python37libscriptspip
    	fmt.Println(filepath.Join(path1, path2, "..", "scripts", "pip"))  // c:python37scriptspip
    	// ..相当于上一层目录
    }
    

    9.Clean(path string) string

    清理路径中的多余字符

    package main
    
    import (
    	"fmt"
    	"path/filepath"
    )
    
    func main() {
    	path := `c:python\python37..\python.ext\aaa.::::\xx`
    	fmt.Println(filepath.Clean(path))  // :pythonpython.extaaa::::xx
    	// 清除的主要是\和\, 都换成了\,个人觉得不是很常用
    }
    

    10.Abs(path string) (string, error)

    获取path的绝对路径,类似于python中的os.path.abspath

    package main
    
    import (
    	"fmt"
    	"path/filepath"
    )
    
    func main() {
    	path1 := `.`
    	abs_path1, err1 := filepath.Abs(path1)
    	if err1 != nil {
    		fmt.Println(err1)
    	}else {
    		fmt.Println(abs_path1)  // D:komeijisatori
    	}
    	
    	//如果是点的话,那么默认是当前go文件所在的工作区的目录
    }
    

    11.IsAbs(path string) bool

    判断当前路径是否是绝对路径

    package main
    
    import (
    	"fmt"
    	"path/filepath"
    )
    
    func main() {
    	path1 := `.`
    	flag := filepath.IsAbs(path1)
    	fmt.Println(flag)  // false
    
    	fmt.Println(filepath.IsAbs(`c:python37python.exe`)) // true
    }
    

    12.VolumeName(path string) string

    返回path所在的卷名,比如c:python37python.exe就是c:,而linux中/opt/python/bin就是/opt/python

    package main
    
    import (
    	"fmt"
    	"path/filepath"
    )
    
    func main() {
    	path1 := `c:python37python.exe`
    	fmt.Println(filepath.VolumeName(path1))  // c:
    }
    

    13.EvalSymlinks(path string) (string, error)

    返回当前链接(快捷方式)所指向的文件

    14.Match(pattern, name string) (matched bool, err error)

    判断 name 是否和指定的模式 pattern 完全匹配,有点类似于python中的fnmatch,但是匹配的方式不太一样

    package main
    
    import (
    	"fmt"
    	"path/filepath"
    )
    
    func main() {
    	/*
    	?:匹配单个任意字符
    	*:匹配任意个任意字符
    	[]:匹配某个范围内的任意一个字符
    	[^]:匹配某个范围外的任意一个字符
    	[a-z]:也可以使用类似于正则表达式的模式,使用-表示一个区间
    	:用来进行转义,匹配实际的字符,比如*表示*, [匹配[,但是?是不需要转义的,因为?表示匹配任意一个字符,所以也包含?
    	[]里面也可以直接包含[ ? *等特殊字符,无需转义。但是] -这些字符则必须要转义,必须是]或者-才能匹配]和-
    	 */
    	fmt.Println(filepath.Match(`???`, "abc"))  // true <nil>
    	fmt.Println(filepath.Match(`???`, "???"))  // true <nil>
    	fmt.Println(filepath.Match(`???`, "abcd"))  // false <nil>
    
    	fmt.Println(filepath.Match(`*`, "abc"))  // true <nil>
    	fmt.Println(filepath.Match(`*`, ""))  // true <nil>
    
    	fmt.Println(filepath.Match(`???[?`, "abc[e"))  // false syntax error in pattern
    
    	fmt.Println(filepath.Match(`[aA][bB][cC]`, `aBc`))  // true <nil>
    	fmt.Println(filepath.Match(`[^aA]*`,`abc`))  // false <nil>
    	fmt.Println(filepath.Match(`[a-z]*`,`a+b`))  // true <nil>
    
    }
    

    15.Glob(pattern string) (matches []string, err error)

    列出与指定的模式 pattern 完全匹配的文件或目录(匹配原则同Match)

    package main
    
    import (
    	"fmt"
    	"io/ioutil"
    	"path/filepath"
    )
    
    func main() {
    	list, err := filepath.Glob(`c:python37*`)
    	if err != nil{
    		fmt.Println(err)
    	}else {
    		for _, v := range list{
    			fmt.Println(v)
    			/*
    			c:python37DLLs
    			c:python37Doc
    			c:python37LICENSE.txt
    			c:python37Lib
    			c:python37NEWS.txt
    			c:python37Scripts
    			c:python37Tools
    			c:python37cx_Oracle-doc
    			c:python37etc
    			c:python37include
    			c:python37libs
    			c:python37man
    			c:python37python.exe
    			c:python37python3.dll
    			c:python37python37.dll
    			c:python37pythonw.exe
    			c:python37share
    			c:python37	cl
    			c:python37vcruntime140.dll
    			 */
    		}
    	}
    
    	//遍历文件还有另一种方式
    	fileinfo, err := ioutil.ReadDir(`c:python37`)
    	if err != nil {
    		fmt.Println(err)
    	}else {
    		// fileinfo则是一个切片,里面的数据类型是os.FileInfo
    		/*
    		type FileInfo interface {
    			Name() string       // base name of the file
    			Size() int64        // length in bytes for regular files; system-dependent for others
    			Mode() FileMode     // file mode bits
    			ModTime() time.Time // modification time
    			IsDir() bool        // abbreviation for Mode().IsDir()
    			Sys() interface{}   // underlying data source (can return nil)
    		}
    		 */
    		for _, v := range fileinfo{
    			message := fmt.Sprintf("文件名:%s,大小:%d,是否是目录,%t", v.Name(), v.Size(), v.IsDir())
    			fmt.Println(message)
    			/*
    			文件名:DLLs,大小:0,是否是目录,true
    			文件名:Doc,大小:0,是否是目录,true
    			文件名:LICENSE.txt,大小:30195,是否是目录,false
    			文件名:Lib,大小:0,是否是目录,true
    			文件名:NEWS.txt,大小:665470,是否是目录,false
    			文件名:Scripts,大小:0,是否是目录,true
    			文件名:Tools,大小:0,是否是目录,true
    			文件名:cx_Oracle-doc,大小:0,是否是目录,true
    			文件名:etc,大小:0,是否是目录,true
    			文件名:include,大小:0,是否是目录,true
    			文件名:libs,大小:0,是否是目录,true
    			文件名:man,大小:0,是否是目录,true
    			文件名:python.exe,大小:99856,是否是目录,false
    			文件名:python3.dll,大小:58896,是否是目录,false
    			文件名:python37.dll,大小:3748368,是否是目录,false
    			文件名:pythonw.exe,大小:98320,是否是目录,false
    			文件名:share,大小:0,是否是目录,true
    			文件名:tcl,大小:0,是否是目录,true
    			文件名:vcruntime140.dll,大小:89752,是否是目录,false
    			 */
    		}
    	}
    }
    

    16.Walk(root string, walkFn WalkFunc) error

    遍历指定目录下的所有子目录,对遍历的项目使用walkFn进行处理,WalkFunc类型如下。

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

    这是最后一个例子,我们多写几个例子 

    package main
    
    import (
    	"fmt"
    	"os"
    	"path/filepath"
    	"strings"
    )
    
    func main() {
    	walkFn := func(path string, info os.FileInfo, err error) error {
    		//遍历的时候,会自动将path:文件路径、info:文件信息、err:错误传递进来,我们可以写上自己的逻辑
    		//获取文件名
    		filename := info.Name()
    		if strings.HasSuffix(filename, "__init__.py"){
    			//如果文件是以__init__.py结尾的话, 直接打印对应的path
    			fmt.Println(path)
    		}
    		//这里我们直接返回nil即可
    		return nil
    	}
    
    	//那么开始遍历,会对遍历的每一个内容都交给walkFn进行处理
    	err := filepath.Walk(`c:python37libsite-packages
    umpy`, walkFn)
    	if err != nil {
    		fmt.Println("err =", err)
    	}
    	/*
    	输出结果
    	c:python37libsite-packages
    umpy\__init__.py
    	c:python37libsite-packages
    umpycompat\__init__.py
    	c:python37libsite-packages
    umpycompat	ests\__init__.py
    	c:python37libsite-packages
    umpycore\__init__.py
    	c:python37libsite-packages
    umpycore	ests\__init__.py
    	c:python37libsite-packages
    umpydistutils\__init__.py
    	c:python37libsite-packages
    umpydistutilscommand\__init__.py
    	c:python37libsite-packages
    umpydistutilsfcompiler\__init__.py
    	c:python37libsite-packages
    umpydistutils	ests\__init__.py
    	c:python37libsite-packages
    umpydoc\__init__.py
    	c:python37libsite-packages
    umpyf2py\__init__.py
    	c:python37libsite-packages
    umpyf2py	ests\__init__.py
    	c:python37libsite-packages
    umpyfft\__init__.py
    	c:python37libsite-packages
    umpyfft	ests\__init__.py
    	c:python37libsite-packages
    umpylib\__init__.py
    	c:python37libsite-packages
    umpylib	ests\__init__.py
    	c:python37libsite-packages
    umpylinalg\__init__.py
    	c:python37libsite-packages
    umpylinalg	ests\__init__.py
    	c:python37libsite-packages
    umpyma\__init__.py
    	c:python37libsite-packages
    umpyma	ests\__init__.py
    	c:python37libsite-packages
    umpymatrixlib\__init__.py
    	c:python37libsite-packages
    umpymatrixlib	ests\__init__.py
    	c:python37libsite-packages
    umpypolynomial\__init__.py
    	c:python37libsite-packages
    umpypolynomial	ests\__init__.py
    	c:python37libsite-packages
    umpy
    andom\__init__.py
    	c:python37libsite-packages
    umpy
    andom	ests\__init__.py
    	c:python37libsite-packages
    umpy	esting\__init__.py
    	c:python37libsite-packages
    umpy	esting\_private\__init__.py
    	c:python37libsite-packages
    umpy	esting	ests\__init__.py
    	c:python37libsite-packages
    umpy	ests\__init__.py
    	 */
    }
    

    统计一下文件个数,分为两个版本,golang版和python版

    • golang

      package main
      
      import (
      	"fmt"
      	"os"
      	"path/filepath"
      	"strings"
      	"time"
      )
      
      func main() {
      	start_time := time.Now().UnixNano()
      	//下面我们来统计一下,c:python37下面有多少个__init__.py文件,有多少个py文件,有多少个不是py文件的文件,有多少个目录
      	init_py_file := 0
      	py_file := 0
      	not_py_file := 0
      	dir := 0
      
      	walkFn := func(path string, info os.FileInfo, err error) error {
      		filename := info.Name()
      		is_dir := info.IsDir()
      		if strings.HasSuffix(filename, "__init__.py") {
      			//如果文件是以__init__.py结尾的话, 别忘了py_file也要++
      			init_py_file++
      			py_file++
      		} else if strings.HasSuffix(filename, ".py") {
      			//以.py结尾的话
      			py_file++
      		} else if is_dir {
      			//如果是目录的话
      			dir++
      		} else {
      			//既不是py结尾,也不是目录的话
      			not_py_file++
      		}
      		//这里我们直接返回nil即可
      		return nil
      	}
      
      	//那么开始遍历,会对遍历的每一个内容都交给walkFn进行处理
      	err := filepath.Walk(`c:python37`, walkFn)
      	if err != nil {
      		fmt.Println("err =", err)
      	}
      	//打印相应的个数
      	fmt.Println(fmt.Sprintf("__init__.py文件个数:%d,py文件个数:%d,不是py文件的文件个数:%d,目录个数:%d", init_py_file, py_file, not_py_file, dir))
      	/*
          __init__.py文件个数:1965,py文件个数:11911,不是py文件的文件个数:23050,目录个数:7685
      	 */
      	end_time := time.Now().UnixNano()
      	fmt.Println("总用时:", (end_time - start_time) / 1e9) // 总用时: 4
      }
      
    • python

      from pathlib import Path
      import os
      import time
      
      start_time = time.perf_counter()
      init_py_file = 0
      py_file = 0
      not_py_file = 0
      dir = 0
      p = Path(r"c:python37")
      for file in p.rglob("*"):
          if str(file).endswith("__init__.py"):
              init_py_file += 1
              py_file += 1
          elif str(file).endswith(".py"):
              py_file += 1
          elif os.path.isdir(str(file)):
              dir += 1
          else:
             not_py_file += 1
      
      end_time = time.perf_counter()
      print(f"__init__.py文件个数:{init_py_file},py文件个数:{py_file},不是py文件的文件个数:{not_py_file},目录个数:{dir}")
      # __init__.py文件个数:1965,py文件个数:11911,不是py文件的文件个数:23050,目录个数:7684
      print(f"总用时:{end_time - start_time}")
      # 总用时:3.695507357
      
    • 总结:两者之间效率基本上是一样的,代码量的话,由于golang的{}多占了一行,并且如果不考虑if err != nil之类的话,代码量也基本差不多。但是我们比较一下结果的话,其他的是一样的,只有目录的个数不一样,golang的结果貌似比python多了一个,这是因为,我们递归遍历的是c:python37,在golang中,把c:python37这个目录本身也给算进去了,而python没有。所以其他的结果是一致的,但是目录个数的话,golang算出来会比python多一个。当然仔细观察结果的话,稍加思考就能发现原因,这里程序就不再演示了,可以找一个文件或目录数量比较少的打印一下,会发现python没有把最外层的目录打印出来,打印都是指定目录里面的内容。

    package main
    
    import (
    	"fmt"
    	"os"
    	"path/filepath"
    )
    
    func main() {
    	walkFn := func(path string, info os.FileInfo, err error) error {
    		is_dir := info.IsDir()
    		if is_dir{
    			//如果是目录,那么我们就跳过,不做处理
    			fmt.Println(fmt.Sprintf("%s是目录,已经跳过", path))
    			return filepath.SkipDir
    		}
    		return nil
    	}
    	//那么开始遍历,会对遍历的每一个内容都交给walkFn进行处理
    	err := filepath.Walk(`c:python37`, walkFn)
    	if err != nil {
    		fmt.Println("err =", err)
    	}
    	/*
    	c:python37是目录,已经跳过
    	 */
    	//可以发现,上来就跳过了,跳过是指整个目录跳过,目录里面有什么也不再关心了
    	//也可以得出,golang是会处理指定的目录,而python不会,python只处理指定目录里面的内容
    }
    
    package main
    
    import (
    	"fmt"
    	"os"
    	"path/filepath"
    )
    
    func main() {
    	walkFn := func(path string, info os.FileInfo, err error) error {
    		filename := info.Name()
    		is_dir := info.IsDir()
    		if is_dir && filename == "scripts"{
    			//如果是目录,并且目录名为scripts,那么我们就跳过,不做处理
    			fmt.Println(fmt.Sprintf("%s是目录,已经跳过", path))
    			return filepath.SkipDir
    		}
    		return nil
    	}
    	//那么开始遍历,会对遍历的每一个内容都交给walkFn进行处理
    	err := filepath.Walk(`c:python37`, walkFn)
    	if err != nil {
    		fmt.Println("err =", err)
    	}
    	/*
    	c:python37Libvenvscripts是目录,已经跳过
    	c:python37Toolsscripts是目录,已经跳过
    	 */
    }
    
  • 相关阅读:
    pid系统控制算法
    pandas+numpy 对df数据中的某列进行等分分桶操作
    pandas学习
    angular6 数组遍历项进行双向绑定 丢失焦点 问题解决
    TypeScript 之构造器 constructor 方法 methods
    公开便民信息网站收集
    C++11_线程池
    百度网盘信息
    【赵强老师】MongoDB中的索引(下)
    TDSQL 4001 备份故障处理案例
  • 原文地址:https://www.cnblogs.com/traditional/p/11409205.html
Copyright © 2011-2022 走看看