python文件路径操作常用方法
前言(文件路径的基本知识)
首先说明路径一般都是字符串的形式,与普通字符串的主要区别在于,普通字符串中的反斜杠(“\”)是表示转义字符的,如换行符(“\n”),跳格符(“\t”),而在路径中,正斜杠(“/”)和反斜杠(“\”)都是用来表示目录分隔符的。
在python中一般用os.path模块来处理路径字符串,对于os.path而言是不区分正斜杠和反斜杠的,将他们一视同仁为目录分隔符,需要注意的是,对于目录分隔符,Unix和Web用正斜杠(“/”),Windows用反斜杠(“\”)。只要提供一个包含斜杠和反斜杠的字符串,都可以用os.path模块处理。
本文所介绍的路径的一些常用操作的模块和方法主要来自于python标准的os库,即在使用前要导入os库:
import os
1.路径的获取和转换
获取当前.py脚本文件的路径
每个python文件自身都有一个__file__
变量存放这当前文件的完整路径,如:
thisPath = __file__
print(thisPath)
输出结果为(以Windows系统为例):
>>d:\python\demo.py
获取绝对路径
通过函数os.path.abspath(str)
来获得绝对路径,参数str
为一个字符串(可以带有斜杠或者反斜杠),该函数并不会去判断参数str
的内容是否为一个存在的目录,最终返回的其实就是根据当前文件所在的路径和str
中的内容组合成一个新的绝对路径,str
中的路径符号支持特殊路径:当前目录(’.’),上一层目录(’…’):
#假设当前目录为“D:\\python\\pathtest”,且不存在任意目录名为“abc”的目录
os.path.abspath(".")
os.path.abspath("..")
os.path.abspath("abc")
os.path.abspath("./abc")
os.path.abspath("../abc")
os.path.abspath("abc/abc")
os.path.abspath("abc/abc/")
上述代码输出结果为:
>'D:\\python\\pathtest'
>'D:\\python'
>'D:\\python\\pathtest\\abc'
>'D:\\python\\pathtest\\abc'
>'D:\\python\\abc'
>'D:\\python\\pathtest\\abc\\abc'
>'D:\\python\\pathtest\\abc\\abc'
路径的规则化
通过函数os.path.normpath(str)
可以将str中的斜杠或者反斜杠(即目录分隔符)按照当前系统的规则进行规范化,注意的是,这个函数并不会判断目录命名中特殊字符是否合法,是否存在反斜杠转义字符的误用,路径文件或目录是否存在等等,仅将目录分隔符即斜杠或反斜杠根据当前系统进行规范化。例如:
os.path.normpath("adba/safa/gae\naf\tsfadsf\ksf\\adsf\\fge/")
显然,参数里的字符串我瞎打的,里面包含了几种情况,最后结果为:
>'adba\\safa\\gae\naf\tsf\x07dsf\\ksf\\adsf\\fge'
可以看到,因为我是在Windows系统下测试的,字符串里的目录分隔符都变为了"\\“,最后多余的斜杠也去掉了,其中”\n",“\t”,“\a"都继续视作转义字符保留了下来,”\\a"是作为正常的目录分隔符和字符处理的。
这个时候,我们测试一下上面的绝对路径获取方式:
os.path.abspath("adba/safa/gae\naf\tsfadsf\ksf\\adsf\\fge/")
输出结果:
>'D:\\python\\pathtest\\adba/safa/gae\naf\tsfadsf\ksf\\adsf\\fge/'
可以看到,os.path.abspath()
函数仅仅是简单的在参数字符串前面增加绝对路径,而没有对参数中的字符串做任何处理,这时候就是os.path.normpath(str)
发挥作用的时候了。
2.路径的判断
判断路径是否存在
用os.path.exists(str)
来判断参数str所代表的路径(无论是目录或者文件都算)是否存在,参数中字符串是绝对路径或相对路径均可,函数自己会去判断。返回值为True或者False。
判断路径是否为文件
os.path.isfile(str)
判断参数str所代表的路径是否为一个文件,如果是则返回True,否则返回False,注意,这里判断的依据是系统定义,而不是简单的通过字符串结尾是否有类似“.txt”这样的文件后缀。例如我在当前目录中创建了一个pathtest.txt的文本文件,之后重命名把后缀“.txt”删了,变成一个无后缀的文件,函数执行结果如下:
>>os.path.isfile("pathtest")
>>True
判断路径是否为目录
os.path.isdir(str)
判断参数str所代表的路径是否为一个目录,如果是则返回True,否则返回False。
3.路径的操作
这里主要介绍的是关于路径字符串的操作,不涉及读取目录内容什么的
路径的分割
os.path.split(str)
这个函数是找到str中最后一个斜杠(准确的说是目录分隔符),然后将该斜杠左边和右边的字符串分割出来,最终返回到一个元组当中,值得注意的是:该函数并不区分系统目录分隔符的规范,斜杠(/)单反斜杠(\)双反斜杠(\\)都会被当做目录分隔符,转义字符除外,且该函数并不关心分割后的右侧到底是文件还是子目录,仅是处理路径字符串而已,所以将其用来从路径中分割出文件名是有一定风险的,需要配合其他函数使用,例如:
>>os.path.split("/python\\pathtest.py")
>>('/python', 'pathtest.py')
>>os.path.split("/python\\pathtest")
>>('/python', 'pathtest')
>>os.path.split("\\python/pathtest")
>>('\\python', 'pathtest')
>> os.path.split("///python\\\\\\pathtest")
('///python', 'pathtest')
>> os.path.split("\\\python//pathtest")
('\\\python', 'pathtest')
>>os.path.split("/python\\pathtest\zxy\nabc")
>>('/python\\pathtest', 'zxy\nabc')
可以看到,函数并不会去区分不同类型的斜杠,一律视作目录分隔符,而且只会寻找参数字符串中最后一个目录分隔符去进行操作,而前面的则保持原样,在最后一个例子中,函数将"\n"视作一个转义字符,但是“\z”并不是任何一个转义字符,所以这里的单反斜杠被视作一个目录分隔符。
下面介绍几种特殊情况,即其中一个元组可能为空的情况:
>>> os.path.split("/python")
('/', 'python')
>>> os.path.split("/python/")
('/python', '')
>>> os.path.split("python/")
('python', '')
>>> os.path.split("python")
('', 'python')
目录的分割还有另外两个函数与os.path.split(str)
有关的:即os.path.dirname(str)
和os.path.basename(str)
,这两个函数内部其实本质调用的就是os.path.split(str)
并分别返回str中最后一个目录分隔符的前半部分和后半部分:
>>> os.path.dirname("python/pathtest")
'python'
>>> os.path.dirname("/python/pathtest")
'/python'
>>> os.path.basename("/python/pathtest")
'pathtest'
路径的合并
os.path.join(str1,str2,...)
函数可以用来将参数中的若干个字符串合并为一个路径,在合并的时候并不会对各个参数中的内容做任何操作,只是将字符串串接起来,只是串接的过程中,在除了最后一个参数以外的所有参数后面都会加一个目录分隔符(遵从当前系统规范),如str1+目录分隔符+str2+目录分隔符+...+strn
,这里在我经过实测的时候发现,有几点需要特别注意的:
1.各个参数中如果有一个或者多个参数的字符串是以目录分隔符(无论是什么形式的)开头的,那么字符串的合并,将以最后一个以目录分隔符开头的字符串开始进行,前面的参数会被忽略:
>>> os.path.join("/abc","/123","/xyz")
'/xyz'
>>> os.path.join("/abc","/123","xyz")
'/123\\xyz'
>>> os.path.join("/abc","123","xyz")
'/abc\\123\\xyz'
>>> os.path.join("abc","123","xyz")
'abc\\123\\xyz'
可以看到,凡是函数自己添加的目录分隔符都会按照当前系统目录分隔符的规范,我测试的时候是Windows系统,所以是反斜杠
2.如果某参数字符串结尾就是目录分隔符,那么在串接合并的时候不会额外增加目录分隔符,因为函数没有添加目录分隔符,而是使用的参数中带的分隔符,所以分隔符可能并没有规范化,使用时要注意,例如:
os.path.join("abc\\","123/","xyz\\\\")
'abc\\123/xyz\\\\'
>>> os.path.join("abc\\","123/\\","xyz\\\\")
'abc\\123/\\xyz\\\\'
>>> os.path.join("abc\\","123/","xyz\\/","test")
'abc\\123/xyz\\/test'
文件扩展名分割
函数os.path.splitext(str)
与路径分割类似,将在参数中寻找最后一个“.”的位置,然后输出这个位置前面和后面的字符串,并不会对字符串中的其他内容做任何操作,测试示例如下:
>>> os.path.splitext("python/test.py")
('python/test', '.py')
>>> os.path.splitext("test.py")
('test', '.py')
>>> os.path.splitext("test..py")
('test.', '.py')
>>> os.path.splitext("python/test")
('python/test', '')
>>> os.path.splitext("python/test.")
('python/test', '.')
>>> os.path.splitext(".py")
('.py', '')
>>> os.path.splitext(".py.txt")
('.py', '.txt')
其中包含了几种特殊情况,看上面代码很容易理解,就不一一说明了。值得注意的是倒数第二个例子,当字符串开头为“.”的时候,这个“.”并不会做文件扩展名分割标识。
4.目录创建与删除
创建目录(文件夹)
os.mkdir(path)
:按照参数path创建目录,可以是相对路径(含特殊路径“./”和“…/”)也可以是绝对路径,要注意的是,该函数只能创建单一目录,即目录的最后一级以前的目录必须是存在的,例如os.mkdir("/python/pathtest/mkdirtest")
,如果“/python/pathtest”路径不存在,会报错,当然,如果创建的目录即"/python/pathtest/mkdirtest"已经存在,也会报错。
递归创建目录
os.makedirs(path)
:按照参数path创建目录,可以是相对路径和绝对路径,只要path所指示的路径不存在,会按照path的目录层级依次建立目录。
删除目录
os.rmdir(path)
:删除path所指代的目录,该目录必须为空目录才可以删除成功,目录不存在或者不为空都会报错。
递归删除目录
os.removedirs(path)
:相比于递归创建目录,这个函数并不怎么好用,我一开始误以为是递归删除path所指代的目录及其中所有子目录以及子目录的子目录。但实际不是,而是从path的最后一级目录开始,逐一往上一级删除,当某一级目录下不为空时,停止删除。
5.路径(目录)下的列表获取
单层路径下的列表获取
os.listdir(path)
:返回路径path下该层级的所有目录名和文件名列表,至于子目录中是否还存在有子目录或者文件是不知道的。
单层路径下的列表详情获取
os.scandir(path)
是python3.5版本以后新增加的,使用的话注意版本兼容问题,可以返回当前路径下所有目录和文件的详细信息,返回的是一个DIREntry对象的迭代器,例如:
xScan = os.scandir("testPath")
for item in xScan:
print("name:",item.name," path:",item.path," isDir:",item.is_dir()," isFile:",item.is_file())
输出结果为:
name: file1.txt path: testPath\file1.txt isDir: False isFile: True
name: file2.txt path: testPath\file2.txt isDir: False isFile: True
name: sub1 path: testPath\sub1 isDir: True isFile: False
name: sub2 path: testPath\sub2 isDir: True isFile: False
注意,实际上sub1和sub2目录下还有子目录和文件,但是os.scandir(path)
仅返回参数目录中单层的目录和文件信息
多层路径下的列表获取
os.walk(path)
:获取path下所有层级目录的目录名及文件名,返回的是以(路径,目录列表,文件列表)为元组的元组生成器(即generator)对象:
>>> x = os.walk("testPath")
>>> print(x,type(x))
<generator object walk at 0x000001BE6FB94F90> <class 'generator'>
具体使用看下面的例子:
# test os.walk()
x = os.walk("testPath")
for paths,dirs,files in x:
print("A tuple:")
print(paths)
print(dirs)
print(files)
x = os.walk("testPath")#由于generator本质是个迭代器,只能遍历一遍所以这里重新取值一次
aTuple = next(x)
print(aTuple,type(aTuple))
aTuple = x.__next__()
print(aTuple,type(aTuple))
输出结果为:
A tuple:
testPath
['sub1', 'sub2']
['file1.txt', 'file2.txt']
A tuple:
testPath\sub1
['subsub1']
['sub1_subsub1_file1.txt']
A tuple:
testPath\sub1\subsub1
[]
['afile.txt']
A tuple:
testPath\sub2
[]
['sub2file1.txt']
('testPath', ['sub1', 'sub2'], ['file1.txt', 'file2.txt']) <class 'tuple'>
('testPath\\sub1', ['subsub1'], ['sub1_subsub1_file1.txt']) <class 'tuple'>
可以看到,os.walk(path)
函数是采取的深度遍历方式遍历路径下的目录和文件。
以上就是一般经常用到的一些路径操作的基本方法,更高级更灵活的使用基本上都是基于上述方法自己实现的。后续如果有需要,在慢慢更新吧。