移除路径中的第一个文件夹
我有一个路径,长得像这样:
/First/Second/Third/Fourth/Fifth
我想把里面的 First
去掉,最终得到:
Second/Third/Fourth/Fifth
我想到的办法是用递归的方式来使用 os.path.split
,但感觉这不是最好的方法。有没有更好的解决办法呢?
5 个回答
我在找有没有简单的方法来实现这个功能,但看起来没有。
我知道这个话题已经有点老了,但这是我找到的最佳解决方案:基本上有两种方法:使用split()和使用len()。这两种方法都需要用到切片。
1) 使用split()
import time
start_time = time.time()
path = "/folder1/folder2/folder3/file.zip"
for i in xrange(500000):
new_path = "/" + "/".join(path.split("/")[2:])
print("--- %s seconds ---" % (time.time() - start_time))
结果:--- 0.420122861862秒 ---
*在new_path = "/" + "/"....这一行中去掉字符"/"并没有显著提高性能。
2) 使用len()。这种方法只有在你提供想要删除的文件夹时才有效
import time
start_time = time.time()
path = "/folder1/folder2/folder3/file.zip"
folder = "/folder1"
for i in xrange(500000):
if path.startswith(folder):
a = path[len(folder):]
print("--- %s seconds ---" % (time.time() - start_time))
结果:--- 0.199596166611秒 ---
*即使加上了检查路径是否以文件名开头的“if”条件,这种方法的速度还是比第一种快了两倍。
总结一下:每种方法都有优缺点。如果你非常确定想要删除的文件夹,使用第二种方法;否则,我建议使用第一种方法,之前有很多人提到过。
这里有一个简单的方法
a = '/First/Second/Third/Fourth/Fifth'
"/".join(a.strip("/").split('/')[1:])
输出结果:
Second/Third/Fourth/Fifth
在上面的代码中,我把字符串分开了,然后把第一个元素去掉,剩下的部分再连接起来。
使用 itertools.dropwhile
:
>>> a = '/First/Second/Third/Fourth/Fifth'
>>> "".join(list(itertools.dropwhile(str.isalnum, a.strip("/"))[1:])
'Second/Third/Fourth/Fifth'
你可以试试:
os.path.relpath(your_path, '/First')
这段话有点像其他的回答,利用了 os.path 这个模块:
os.path.join(*(x.split(os.path.sep)[2:]))
... 假设你的字符串是以一个分隔符开头的。
其实在 os.path
这个模块里并没有直接可以做到这个的功能。偶尔会有人提议创建一个 splitall
函数,能返回一个包含所有部分的列表(或者迭代器),但这个想法一直没有得到广泛支持。
部分原因是,每次有人建议在 os.path
中添加新功能时,都会引发对这个库设计的不满,导致有人提议用一个更面向对象的路径API来替代这个笨重的 os
API。在3.4版本中,这个提议终于实现了,推出了 pathlib
。而且它已经有了 os.path
中没有的功能。所以:
>>> import pathlib
>>> p = pathlib.Path('/First/Second/Third/Fourth/Fifth')
>>> p.parts[2:]
('Second', 'Third', 'Fourth', 'Fifth')
>>> pathlib.Path(*p.parts[2:])
PosixPath('Second/Third/Fourth/Fifth')
或者……你确定你真的想去掉第一个部分,而不是这样做吗?
>>> p.relative_to(*p.parts[:2])
PosixPath('Second/Third/Fourth/Fifth')
如果你需要在2.6-2.7或3.2-3.3版本中做到这一点,可以使用 pathlib的回溯版本。
当然,你也可以使用字符串操作,只要你小心地规范化路径,使用 os.path.sep
,并确保处理好一些麻烦的细节,比如非绝对路径或者带有驱动器字母的系统等等……
或者你可以把你的递归 os.path.split
封装起来。封装之后,究竟有什么地方是“不够优化”的呢?可能会稍微慢一点,但我们说的是纳秒级的差别,这比调用文件的 stat
快得多。如果你的文件系统有1000层目录,可能会遇到递归深度的问题,但你见过这样的文件系统吗?(如果见过,你总是可以把它改成循环的……)封装起来并写好单元测试只需要几分钟,但这只是一次性的事情,以后就不用再担心了。所以,老实说,如果你不想使用 pathlib
,我会选择这样做。