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:\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:处理文件路径的一把好手的更多相关文章
- C#文件路径乱码
最近学C#,用C#写serialport遇到了一点小问题记录一下. 问题一: if (!string.IsNullOrEmpty(filePath.ToString())) { try { fs = ...
- chrome文件上传 /获取文件路径c:/fakepath的解决办法
jsp页面 <td style="text-align: left;padding-left: 20px;"> <img name="image&quo ...
- 文件指针/句柄(FILE*)、文件描述符(fd)以及 文件路径(filepath)的相互转换(转)
转自: http://blog.csdn.net/jenghau/article/details/5532265 文件指针/句柄(FILE*).文件描述符(fd)以及 文件路径(filepath)的相 ...
- Go path/filepath文件路径操作
本文:https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter06/06.2.html path:htt ...
- Excel公式 提取文件路径后缀
我们在代码中获取一个文件路径的后缀,是一个很简单的事. 如C#中,可以通过new FileInfo(filePath).Extension,或者Path.GetExtension(filePath)获 ...
- Ruby操作VBA的注意事项和技巧(1):乱码、获取VBA活动和非活动窗口的名称与路径、文件路径的智能拼接与截取(写入日期)
1.VBA编辑器复制粘贴出来的代码乱码 解决方法:切换到中文输入模式再复制出来就行了 2.获取VBA活动和非活动窗口的名称与路径 Dim wbpath, filename As String ...
- iOS获取文件路径
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px "PingFang SC"; color: #008400 } p.p2 ...
- oc 根据文件路径获取文件大小
第一种封装: -(NSInteger)getSizeOfFilePath:(NSString *)filePath{ /** 定义记录大小 */ NSInteger totalSize = ; /** ...
- .35-浅析webpack源码之babel-loader入口文件路径读取
在处理./input.js入口文件时,在类型判断被分为普通文件,所以走的文件事件流,最后拼接得到文件的绝对路径. 但是对应"babel-loader"这个字符串,在如下正则中被判定 ...
随机推荐
- 数据解析框架之FastJson
演示实体类 import java.util.List; public class Student { public String name; public int age; public List& ...
- 内存数据库:Redis与Memcached的区别
Redis与Memcached的区别 传统MySQL+ Memcached架构遇到的问题 实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都 ...
- Java调用Redis集群
前文 需要使用以下jar包 Maven项目引用以下配置: <dependency> <groupId>org.apache.commons</groupId> &l ...
- centOS 开启端口
生产环境禁止关闭防火墙,只能开端口 [root@BetaD home]# firewall-cmd --add-port=/tcp --permanent [root@BetaD home]# fir ...
- configmap使用-完整的configmap文档
转发 https://www.jianshu.com/p/cf3e2218f283 转发 https://www.kubernetes.org.cn/3138.html 注意:configmap不用也 ...
- Window Relationships and Frames
If a page contains frames, each frame has its own window object and is stored in the frames collecti ...
- Centos7下yum安装kubernetes
一.前言 Kubernetes 是Google开源的容器集群管理系统,基于Docker构建一个容器的调度服务,提供资源调度.均衡容灾.服务注册.动态扩缩容等功能套件,目前centos yum源上 ...
- PJzhang:今天才搞清身份证、银行卡……的编码规则
猫宁!!! 之前思考过常见证件的编码规则,抽空查了一下,发现挺有意思. 一般查询证件或者手机号归属地都是直接百度小工具,但是背后的查询机制如何,可能大多人不甚了解. 介绍几种生活中最 ...
- MAC使用二进制方式安装Mysql 5.7
一.参考文档: 二.基础环境: 系统:Centos7.4 mysql版本:percona mysql 5.7 三.部署mysql 1.初始化 mysqld --initialize --explici ...
- Java小技巧:怎么循环日期?
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");try{//起始日期Date start = sdf.parse ...