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:\python37\python.exe`)) // C:/python37/python.exe // 注意:该函数不在意路径是否存在,只是当成普通的字符串进行处理
// 比如我输入一个不存在的路径也是可以的
fmt.Println(filepath.ToSlash(`C:\python37\python.exe\python.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:\python37\python.exe
fmt.Println(filepath.FromSlash(`C:\python37/python.exe`)) // C:\python37\python.exe
fmt.Println(filepath.FromSlash(`C:\python37\python.exe////`)) // C:\python37\python.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:\python37\python.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:\python37\python.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:\python37\python.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:\python37\python.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:\python37\python.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:\python37\python.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:\python37\lib\site-packages\tornado fmt.Println(filepath.Join(path1, path2, "scripts", "pip")) // c:\python37\lib\scripts\pip
fmt.Println(filepath.Join(path1, path2, "..", "scripts", "pip")) // c:\python37\scripts\pip
// ..相当于上一层目录
}

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)) // :\python\python.ext\aaa\::::\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:\python37\python.exe`)) // true
}

12.VolumeName(path string) string

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

package main

import (
"fmt"
"path/filepath"
) func main() {
path1 := `c:\python37\python.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:\python37\DLLs
c:\python37\Doc
c:\python37\LICENSE.txt
c:\python37\Lib
c:\python37\NEWS.txt
c:\python37\Scripts
c:\python37\Tools
c:\python37\cx_Oracle-doc
c:\python37\etc
c:\python37\include
c:\python37\libs
c:\python37\man
c:\python37\python.exe
c:\python37\python3.dll
c:\python37\python37.dll
c:\python37\pythonw.exe
c:\python37\share
c:\python37\tcl
c:\python37\vcruntime140.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:\python37\lib\site-packages\numpy`, walkFn)
if err != nil {
fmt.Println("err =", err)
}
/*
输出结果
c:\python37\lib\site-packages\numpy\__init__.py
c:\python37\lib\site-packages\numpy\compat\__init__.py
c:\python37\lib\site-packages\numpy\compat\tests\__init__.py
c:\python37\lib\site-packages\numpy\core\__init__.py
c:\python37\lib\site-packages\numpy\core\tests\__init__.py
c:\python37\lib\site-packages\numpy\distutils\__init__.py
c:\python37\lib\site-packages\numpy\distutils\command\__init__.py
c:\python37\lib\site-packages\numpy\distutils\fcompiler\__init__.py
c:\python37\lib\site-packages\numpy\distutils\tests\__init__.py
c:\python37\lib\site-packages\numpy\doc\__init__.py
c:\python37\lib\site-packages\numpy\f2py\__init__.py
c:\python37\lib\site-packages\numpy\f2py\tests\__init__.py
c:\python37\lib\site-packages\numpy\fft\__init__.py
c:\python37\lib\site-packages\numpy\fft\tests\__init__.py
c:\python37\lib\site-packages\numpy\lib\__init__.py
c:\python37\lib\site-packages\numpy\lib\tests\__init__.py
c:\python37\lib\site-packages\numpy\linalg\__init__.py
c:\python37\lib\site-packages\numpy\linalg\tests\__init__.py
c:\python37\lib\site-packages\numpy\ma\__init__.py
c:\python37\lib\site-packages\numpy\ma\tests\__init__.py
c:\python37\lib\site-packages\numpy\matrixlib\__init__.py
c:\python37\lib\site-packages\numpy\matrixlib\tests\__init__.py
c:\python37\lib\site-packages\numpy\polynomial\__init__.py
c:\python37\lib\site-packages\numpy\polynomial\tests\__init__.py
c:\python37\lib\site-packages\numpy\random\__init__.py
c:\python37\lib\site-packages\numpy\random\tests\__init__.py
c:\python37\lib\site-packages\numpy\testing\__init__.py
c:\python37\lib\site-packages\numpy\testing\_private\__init__.py
c:\python37\lib\site-packages\numpy\testing\tests\__init__.py
c:\python37\lib\site-packages\numpy\tests\__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:\python37\Lib\venv\scripts是目录,已经跳过
c:\python37\Tools\scripts是目录,已经跳过
*/
}

filepath:处理文件路径的一把好手的更多相关文章

  1. C#文件路径乱码

    最近学C#,用C#写serialport遇到了一点小问题记录一下. 问题一: if (!string.IsNullOrEmpty(filePath.ToString())) { try { fs = ...

  2. chrome文件上传 /获取文件路径c:/fakepath的解决办法

    jsp页面 <td style="text-align: left;padding-left: 20px;"> <img name="image&quo ...

  3. 文件指针/句柄(FILE*)、文件描述符(fd)以及 文件路径(filepath)的相互转换(转)

    转自: http://blog.csdn.net/jenghau/article/details/5532265 文件指针/句柄(FILE*).文件描述符(fd)以及 文件路径(filepath)的相 ...

  4. Go path/filepath文件路径操作

    本文:https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter06/06.2.html path:htt ...

  5. Excel公式 提取文件路径后缀

    我们在代码中获取一个文件路径的后缀,是一个很简单的事. 如C#中,可以通过new FileInfo(filePath).Extension,或者Path.GetExtension(filePath)获 ...

  6. Ruby操作VBA的注意事项和技巧(1):乱码、获取VBA活动和非活动窗口的名称与路径、文件路径的智能拼接与截取(写入日期)

    1.VBA编辑器复制粘贴出来的代码乱码     解决方法:切换到中文输入模式再复制出来就行了 2.获取VBA活动和非活动窗口的名称与路径 Dim wbpath, filename As String ...

  7. iOS获取文件路径

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px "PingFang SC"; color: #008400 } p.p2 ...

  8. oc 根据文件路径获取文件大小

    第一种封装: -(NSInteger)getSizeOfFilePath:(NSString *)filePath{ /** 定义记录大小 */ NSInteger totalSize = ; /** ...

  9. .35-浅析webpack源码之babel-loader入口文件路径读取

    在处理./input.js入口文件时,在类型判断被分为普通文件,所以走的文件事件流,最后拼接得到文件的绝对路径. 但是对应"babel-loader"这个字符串,在如下正则中被判定 ...

随机推荐

  1. 数据解析框架之FastJson

    演示实体类 import java.util.List; public class Student { public String name; public int age; public List& ...

  2. 内存数据库:Redis与Memcached的区别

    Redis与Memcached的区别 传统MySQL+ Memcached架构遇到的问题 实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都 ...

  3. Java调用Redis集群

    前文 需要使用以下jar包 Maven项目引用以下配置: <dependency> <groupId>org.apache.commons</groupId> &l ...

  4. centOS 开启端口

    生产环境禁止关闭防火墙,只能开端口 [root@BetaD home]# firewall-cmd --add-port=/tcp --permanent [root@BetaD home]# fir ...

  5. configmap使用-完整的configmap文档

    转发 https://www.jianshu.com/p/cf3e2218f283 转发 https://www.kubernetes.org.cn/3138.html 注意:configmap不用也 ...

  6. Window Relationships and Frames

    If a page contains frames, each frame has its own window object and is stored in the frames collecti ...

  7. Centos7下yum安装kubernetes

    一.前言    Kubernetes 是Google开源的容器集群管理系统,基于Docker构建一个容器的调度服务,提供资源调度.均衡容灾.服务注册.动态扩缩容等功能套件,目前centos yum源上 ...

  8. PJzhang:今天才搞清身份证、银行卡……的编码规则

    猫宁!!! ​​   之前思考过常见证件的编码规则,抽空查了一下,发现挺有意思.   一般查询证件或者手机号归属地都是直接百度小工具,但是背后的查询机制如何,可能大多人不甚了解.   介绍几种生活中最 ...

  9. MAC使用二进制方式安装Mysql 5.7

    一.参考文档: 二.基础环境: 系统:Centos7.4 mysql版本:percona mysql 5.7 三.部署mysql 1.初始化 mysqld --initialize --explici ...

  10. Java小技巧:怎么循环日期?

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");try{//起始日期Date start = sdf.parse ...