无论使用哪种操作系统或路径格式,我都可以使用哪个Python库从路径中提取文件名?例如,我希望所有这些路径都可以返回c

a/b/c/
a/b/c
\a\b\c
\a\b\c\
a\b\c
a/b/../../a/b/c/
a/b/../../a/b/c


#1 楼

像其他建议一样使用os.path.splitos.path.basename在所有情况下都无法正常工作:如果您在Linux上运行脚本并尝试处理经典的Windows样式路径,则它将失败。

Windows路径可以使用反斜杠或正斜杠作为路径分隔符。因此,ntpath模块(在Windows上运行时等效于os.path)将在所有平台上的all(1)路径上正常工作。

import ntpath
ntpath.basename("a/b/c")


当然,如果文件以斜杠结尾,则基名将为空,因此请使用您自己的函数进行处理:

def path_leaf(path):
    head, tail = ntpath.split(path)
    return tail or ntpath.basename(head)


验证:

>>> paths = ['a/b/c/', 'a/b/c', '\a\b\c', '\a\b\c\', 'a\b\c', 
...     'a/b/../../a/b/c/', 'a/b/../../a/b/c']
>>> [path_leaf(path) for path in paths]
['c', 'c', 'c', 'c', 'c', 'c', 'c']




(1)有一个警告:Linux文件名可能包含反斜杠。因此,在Linux上,r'a/b\c'始终引用b\c文件夹中的文件a,而在Windows上,它始终引用c文件夹的b子文件夹中的a文件。因此,在路径中同时使用正斜杠和反斜杠时,您需要了解关联的平台才能正确解释它。实际上,通常可以安全地假定它是Windows路径,因为Linux文件名中很少使用反斜杠,但是在编写代码时请记住这一点,以免造成意外的安全漏洞。

评论


在Windows上,os.path只是在内部加载ntpath模块。使用此模块,即使在Linux机器上也可以处理'\\'路径分隔符。对于Linux,posixpath模块(resp。os.path)将简化路径操作,仅允许使用posix样式'/'分隔符。

–moooeeeep
2011-12-5 12:27



@moooeeeep所以我们可以使用Stranac的答案,它可靠吗? (“按照其他建议使用os.path.split或os.path.basename并非在所有情况下都有效:如果您在Linux上运行脚本并尝试处理经典的Windows样式路径,它将失败”- -引言来自劳里兹(Lauritz)的帖子-我不明白,这个警告是否涉及Stranac的回答?

–约翰c。 j。
17年4月1日在20:40



@ johnc.j。仅当您需要在Linux机器上解析Windows样式路径(例如r'C:\ path \ to \ file.txt')时,才需要使用ntpath模块。否则,您可以使用os.path中的功能。这是因为Linux系统通常允许在文件名中使用反斜杠字符(如答案中所述)。

–moooeeeep
17-4-3在7:07



您的解决方案不等于os.path.basename(os.path.normpath(path))吗?

– Mr_and_Mrs_D
17年6月25日在13:14

对于将来访问此问题的人来说有价值的是,我遇到了劳里茨警告的情况,而他的解决方案是唯一可行的解​​决方案。使用os时,不能仅输出文件名。因此,恕我直言,ntpath是必经之路。

– Harabeck
18年1月19日在17:40

#2 楼

实际上,有一个函数可以完全返回您想要的内容
警告:在POSIX系统上使用os.path.basename()从Windows样式的路径(例如"C:\my\file.txt")中获取基本名称时,整个路径将是返回。
以下示例在Linux主机上运行的交互式python shell中:
import os
print(os.path.basename(your_path))


评论


如果要以独立于OS的方式处理路径,则对于os.path.basename(u“ C:\\ temp \\ bla.txt”)您将期望获得'bla.txt'。问题不是关于获取有效的文件名,而是提取路径的名称。

– Adi Roiban
2014年1月25日在11:07



在我的Google搜索中,找到路径的文件名时,此答案最有帮助。无论如何,我的用例仅在Windows上。

– Bobort
16 Nov 15在15:12



os.path.basename(your_path)可行!我想要脚本路径:os.path.dirname(os.path.realpath(__ file__))和脚本名称:os.path.basename(os.path.realpath(__ file__))。谢谢!

– TheWalkingData
17年2月21日在18:23

@AdiRoiban请您详细说明一下?我在Windows 7上进行了测试,实际上得到的是“ bla.txt”。简而言之,我没有发现任何问题。

–约翰c。 j。
17年4月1日在20:50



@ johnc.j。关键是,当您在Linux上尝试执行此操作时,将获得“ C:\\ temp \\ bla.txt”。

–moooeeeep
17-4-3在6:58



#3 楼

os.path.split
是您要寻找的功能

head, tail = os.path.split("/tmp/d/a.dat")

>>> print(tail)
a.dat
>>> print(head)
/tmp/d


评论


为了使其他用户注意,如果路径以“ /”或“ \”结尾,则返回“”

– BuZz
2011-12-5 11:50

当我尝试“ C:\ Users \ Dell \ Desktop \ ProjectShadow \ button \ button.py”时,除此以外,它都会返回“ ProjectShadowuttontton”,它会返回正确的结果

– amitnair92
17年1月19日在12:38



@ amitnair92-执行以下操作:r“ C:\ Users \ Dell \ Desktop \ ProjectShadow \ button \ button.py”或执行以下操作:“ C:\\ Users \\ Dell \\ Desktop \\ ProjectShadow \\ button \\ button .py“-” \ b“是一个特殊字符(我认为是系统的“钟”),类似于\ r或\ n表示换行符/回车符的方式。用r“ C:\ ...”前缀字符串意味着使用给定的原始输入

–布鲁斯·拉蒙德(Bruce Lamond)
17年1月31日,0:53



#4 楼

在python 3中

>>> from pathlib import Path    
>>> Path("/tmp/d/a.dat").name
'a.dat'


评论


3.4至3.6或更高版本,具体取决于您使用的pathlib项。

– LightCC
19-09-25在20:34

也可以使用Path(“ some / path / to / file.dat”)。stem获取没有文件扩展名的文件名

– s2t2
19年11月14日在22:51

#5 楼

import os
head, tail = os.path.split('path/to/file.exe')


所需的是文件名。

有关详细信息,请参见python os模块文档

评论


为了使其他用户注意,如果路径以“ /”或“ \”结尾,则返回“”

– BuZz
2011-12-5 11:50

#6 楼

 import os
file_location = '/srv/volume1/data/eds/eds_report.csv'
file_name = os.path.basename(file_location )  #eds_report.csv
location = os.path.dirname(file_location )    #/srv/volume1/data/eds
 


#7 楼

fname = str("C:\Windows\paint.exe").split('\')[-1:][0]


这将返回:paint.exe


更改与您的路径或OS有关的split函数的sep值。


评论


这是我喜欢的答案,但为什么不执行以下操作呢? fname = str(path).split('/')[-1]

–asultan904
2月25日18:48



#8 楼

如果要自动获取文件名,可以执行

import glob

for f in glob.glob('/your/path/*'):
    print(os.path.split(f)[-1])


#9 楼

在您的示例中,您还需要从右侧去除斜线以返回c

>>> import os
>>> path = 'a/b/c/'
>>> path = path.rstrip(os.sep) # strip the slash from the right side
>>> os.path.basename(path)
'c'


第二级:

>>> os.path.filename(os.path.dirname(path))
'b'


更新:我认为lazyr提供了正确的答案。我的代码不适用于unix系统上类似Windows的路径,反之亦然,不适用于Windows系统上类似unix的路径。

评论


您的答案不适用于Linux上的r“ a \ b \ c”或Windows上的“ a / b / c”。

–Lauritz V. Thaulow
2011年12月5日12:00

当然,os.path.basename(path)仅在os.path.isfile(path)为True时才有效。因此path ='a / b / c /'根本不是有效的文件名...

–moooeeeep
2011-12-5 12:04

@fmaas os.path.basename纯粹是一个字符串处理函数。不管文件是否存在,或者它是文件还是目录。 os.path.basename(“ a / b / c /”)由于出现斜杠而返回“”。

–Lauritz V. Thaulow
2011-12-5 12:09

懒惰的你是对的!我没想到只做path = path.replace('\\','/')是否安全?

–滑雪
2011-12-5 12:12



我想@@ Skirmantas,但是感觉不对。我认为路径处理应使用为该工作量身定制的内置工具来完成。路径比目睹更多。

–Lauritz V. Thaulow
2011-12-5 12:22



#10 楼

如果您的文件路径不以“ /”结尾并且目录以“ /”分隔,则使用以下代码。众所周知,路径通常不以“ /”结尾。

import os
path_str = "/var/www/index.html"
print(os.path.basename(path_str))


但是在某些情况下,例如URL以“ /”结尾,请使用以下代码

import os
path_str = "/home/some_str/last_str/"
split_path = path_str.rsplit("/",1)
print(os.path.basename(split_path[0]))


,但是当您的路径通常在Windows路径中以“ \”分隔时,则可以使用以下代码

import os
path_str = "c:\var\www\index.html"
print(os.path.basename(path_str))

import os
path_str = "c:\home\some_str\last_str\"
split_path = path_str.rsplit("\",1)
print(os.path.basename(split_path[0]))


您可以通过检查OS类型将两者组合为一个函数并返回结果。

#11 楼

这也适用于具有标准库的Linux和Windows。

paths = ['a/b/c/', 'a/b/c', '\a\b\c', '\a\b\c\', 'a\b\c',
         'a/b/../../a/b/c/', 'a/b/../../a/b/c']

def path_leaf(path):
    return path.strip('/').strip('\').split('/')[-1].split('\')[-1]

[path_leaf(path) for path in paths]


结果:

['c', 'c', 'c', 'c', 'c', 'c', 'c']


#12 楼

这是仅用于正则表达式的解决方案,似乎可以与任何OS上的任何OS路径一起使用。

不需要其他模块,也不需要预处理:

import re

def extract_basename(path):
  """Extracts basename of a given path. Should Work with any OS Path on any OS"""
  basename = re.search(r'[^\/]+(?=[\/]?$)', path)
  if basename:
    return basename.group(0)


paths = ['a/b/c/', 'a/b/c', '\a\b\c', '\a\b\c\', 'a\b\c',
         'a/b/../../a/b/c/', 'a/b/../../a/b/c']

print([extract_basename(path) for path in paths])
# ['c', 'c', 'c', 'c', 'c', 'c', 'c']


extra_paths = ['C:\', 'alone', '/a/space in filename', 'C:\multi\nline']

print([extract_basename(path) for path in extra_paths])
# ['C:', 'alone', 'space in filename', 'multi\nline']


更新:

如果仅希望潜在的文件名(如果存在)(即/a/b/是dir,c:\windows\也是),则将正则表达式更改为:r'[^\/]+(?![\/])$'。对于“正则表达式挑战”,这会将某种斜杠的正向正向查找改为负向正向向前查找,导致以所述斜杠结尾的路径名不返回任何内容,而不返回路径名中的最后一个子目录。当然,不能保证潜在的文件名实际上是指文件,并且需要使用os.path.is_dir()os.path.is_file()

这将匹配以下内容:

/a/b/c/             # nothing, pathname ends with the dir 'c'
c:\windows\         # nothing, pathname ends with the dir 'windows'
c:hello.txt         # matches potential filename 'hello.txt'
~it_s_me/.bashrc    # matches potential filename '.bashrc'
c:\windows\system32 # matches potential filename 'system32', except
                    # that is obviously a dir. os.path.is_dir()
                    # should be used to tell us for sure


regex可以在这里进行测试。

评论


您正在使用re,为什么不使用os模块?

– Saurabh Chandra Patel
4月15日下午5:17

@SaurabhChandraPatel已经很长时间了。如果我没记错的话,在这种情况下,将正则表达式用作跨平台解决方案。例如,您可以在Linux服务器上处理Windows文件名。

–埃里克·杜米尼尔(Eric Duminil)
4月15日下午7:21

#13 楼

也许只是我的全能解决方案,而没有任何重要的新内容(关于创建临时文件的临时文件:D)

import tempfile
abc = tempfile.NamedTemporaryFile(dir='/tmp/')
abc.name
abc.name.replace("/", " ").split()[-1] 


获取abc.name的值将是这样的字符串:'/tmp/tmpks5oksk7'
所以我可以将/替换为空格.replace("/", " "),然后致电split()。这将返回一个列表,我用[-1]得到列表的最后一个元素

无需导入任何模块。

评论


如果文件名或目录包含空格怎么办?

– kriss
15-10-16在8:46

直接拆分(“ /”)[-1]怎么样?

–南
19-10-5在7:38

#14 楼

我从未见过双反斜线路径,它们是否存在? python模块os的内置功能对此无效。其他所有方法都起作用,也由您给出os.path.normpath()的警告:

paths = ['a/b/c/', 'a/b/c', '\a\b\c', '\a\b\c\', 'a\b\c', 
...     'a/b/../../a/b/c/', 'a/b/../../a/b/c', 'a/./b/c', 'a\b/c']
for path in paths:
    os.path.basename(os.path.normpath(path))


评论


那些不是双重背景。它们是单个反斜杠,因此需要转义。

–埃里克·杜米尼尔(Eric Duminil)
19年6月23日在12:59

#15 楼

Windows分隔符可以在Unix文件名或Windows路径中。 Unix分隔符只能存在于Unix路径中。 Unix分隔符的存在指示非Windows路径。

以下内容将由OS特定的分隔符剥离(剪切尾随的分隔符),然后进行分隔并返回最右边的值。这很丑陋,但基于上面的假设很简单。如果假设不正确,请更新,我将更新此响应以匹配更准确的条件。

a.rstrip("\\" if a.count("/") == 0 else '/').split("\\" if a.count("/") == 0 else '/')[-1]


示例代码:

b = ['a/b/c/','a/b/c','\a\b\c','\a\b\c\','a\b\c','a/b/../../a/b/c/','a/b/../../a/b/c']

for a in b:

    print (a, a.rstrip("\" if a.count("/") == 0 else '/').split("\" if a.count("/") == 0 else '/')[-1])


评论


另外,请随时向我发送有关如何在此场所进行格式化的指示。尝试了六次以使示例代码正确。

–dusc2don
16年5月16日在14:37

#16 楼

为了完整起见,这是适用于python 3.2+的pathlib解决方案:

>>> from pathlib import PureWindowsPath

>>> paths = ['a/b/c/', 'a/b/c', '\a\b\c', '\a\b\c\', 'a\b\c', 
...          'a/b/../../a/b/c/', 'a/b/../../a/b/c']

>>> [PureWindowsPath(path).name for path in paths]
['c', 'c', 'c', 'c', 'c', 'c', 'c']


这在Windows和Linux上均可使用。

#17 楼

在Python 2和3中,使用模块pathlib2:

import posixpath  # to generate unix paths
from pathlib2 import PurePath, PureWindowsPath, PurePosixPath

def path2unix(path, nojoin=True, fromwinpath=False):
    """From a path given in any format, converts to posix path format
    fromwinpath=True forces the input path to be recognized as a Windows path (useful on Unix machines to unit test Windows paths)"""
    if not path:
        return path
    if fromwinpath:
        pathparts = list(PureWindowsPath(path).parts)
    else:
        pathparts = list(PurePath(path).parts)
    if nojoin:
        return pathparts
    else:
        return posixpath.join(*pathparts)


用法:

In [9]: path2unix('lala/lolo/haha.dat')
Out[9]: ['lala', 'lolo', 'haha.dat']

In [10]: path2unix(r'C:\lala/lolo/haha.dat')
Out[10]: ['C:\', 'lala', 'lolo', 'haha.dat']

In [11]: path2unix(r'C:\lala/lolo/haha.dat') # works even with malformatted cases mixing both Windows and Linux path separators
Out[11]: ['C:\', 'lala', 'lolo', 'haha.dat']


测试用例:

In [12]: testcase = paths = ['a/b/c/', 'a/b/c', '\a\b\c', '\a\b\c\', 'a\b\c',
    ...: ...     'a/b/../../a/b/c/', 'a/b/../../a/b/c']

In [14]: for t in testcase:
    ...:     print(path2unix(t)[-1])
    ...:
    ...:
c
c
c
c
c
c
c


这里的想法是将所有路径转换为pathlib2的统一内部表示形式,并根据平台使用不同的解码器。幸运的是,pathlib2包含一个可在任何路径上工作的通用解码器PurePath。如果这不起作用,则可以使用fromwinpath=True强制识别Windows路径。这会将输入字符串分割成几部分,最后一个是您要查找的叶子,因此是path2unix(t)[-1]

如果参数nojoin=False,则路径将被重新连接,因此输出很简单将输入字符串转换为Unix格式,这可用于比较跨平台的子路径。

#18 楼

我个人最喜欢的是:
filename = fullname.split(os.sep)[-1]