ChatGPT解决这个技术问题 Extra ChatGPT

从路径中提取文件名,无论 os/path 格式如何

无论操作系统或路径格式是什么,我都可以使用哪个 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
更新,因为答案是较旧的方法。 standard library: pathlib.Path 就是为此而设计的

J
Joshua Schlichting

实际上,有一个 function 可以准确返回您想要的

import os
print(os.path.basename(your_path))

警告:当在 POSIX 系统上使用 os.path.basename() 从 Windows 样式路径(例如 "C:\\my\\file.txt")获取基本名称时,将返回整个路径。

以下示例来自在 Linux 主机上运行的交互式 python shell:

Python 3.8.2 (default, Mar 13 2020, 10:14:16)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> filepath = "C:\\my\\path\\to\\file.txt" # A Windows style file path.
>>> os.path.basename(filepath)
'C:\\my\\path\\to\\file.txt'

如果您想以独立于操作系统的方式处理路径,那么对于 os.path.basename(u"C:\\temp\\bla.txt") 您期望得到 'bla.txt' 。问题不在于获取有效的文件名,而是提取路径的名称。
在我的谷歌搜索中寻找路径的文件名,这个答案是最有帮助的。无论如何,我的用例仅在 Windows 上。
os.path.basename(your_path) 这行得通!我想要脚本路径:os.path.dirname(os.path.realpath(__file__)) 和脚本名称:os.path.basename(os.path.realpath(__file__))。谢谢!
@johnc.j。关键是,当您在 Linux 上尝试此操作时,您会得到 'C:\\temp\\bla.txt'
@stranac你是对的,这是Linux实现以自我为中心的,不将路径中的反斜杠视为正确的路径分隔符。从好的方面来说,Windows 风格的路径 do 在 Linux 上工作,但您必须使用 仅正斜杠(这样您就可以做到 {1 } 在这里获得一些平台独立性)
L
Lauritz V. Thaulow

像其他人建议的那样使用 os.path.splitos.path.basename 并不适用于所有情况:如果您在 Linux 上运行脚本并尝试处理经典的 windows 样式路径,它将失败。

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

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

当然,如果文件以斜杠结尾,则 basename 将为空,因此请自己编写函数来处理它:

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' 总是指 a 文件夹中的文件 b\c,而在 Windows 上,它总是指 a 文件夹的 b 子文件夹中的 c 文件。因此,当路径中同时使用正斜杠和反斜杠时,您需要知道相关的平台才能正确解释它。实际上,通常可以安全地假设它是 Windows 路径,因为反斜杠很少用于 Linux 文件名,但在编写代码时请记住这一点,以免造成意外的安全漏洞。


在 Windows 上,os.path 只是在内部加载 ntpath 模块。使用这个模块,即使在 Linux 机器上也可以处理 '\\' 路径分隔符。对于 Linux,posixpath 模块(resp. os.path)将简化路径操作以仅允许 posix 样式的 '/' 分隔符。
@moooeeeep所以我们可以使用Stranac的答案,它可靠吗? (“像其他人建议的那样使用 os.path.split 或 os.path.basename 并非在所有情况下都有效:如果您在 Linux 上运行脚本并尝试处理经典的 windows 样式路径,它将失败” - - 引用来自劳里茨的帖子 - 我不明白,这个警告是否与斯特拉纳克的回答有关)。
@johnc.j。只有当您需要在 Linux 机器上解析 Windows 风格的路径(例如,r'C:\path\to\file.txt')时,您才需要使用 ntpath 模块。否则,您可以使用 os.path 中的函数。这是因为 Linux 系统通常允许在文件名中使用反斜杠字符(如答案中所述)。
您的解决方案不等同于 os.path.basename(os.path.normpath(path)) 吗?
对于这个问题的未来访问者来说,我遇到了劳里茨警告的情况,他的解决方案是唯一有效的解决方案。没有使用 os 的任何方法都可以只输出文件名。所以恕我直言,ntpath 是要走的路。
M
Martin Thoma

os.path.split 是您正在寻找的功能

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

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

只是为了让其他用户小心,如果路径以“/”或“\”结尾,则返回“”
当我尝试“C:\Users\Dell\Desktop\ProjectShadow\button\button.py”时,它会为除此之外的所有内容返回“ProjectShadowuttontton”,它会返回正确的结果
@amitnair92 - 要么这样做:r"C:\Users\Dell\Desktop\ProjectShadow\button\button.py" 要么这样做:"C:\\Users\\Dell\\Desktop\\ProjectShadow\\button\\button .py" - "\b" 是一个特殊字符(我认为是系统'bell'),类似于 \r 或 \n 表示换行符/回车符的方式。使用 r"C:\..." 为字符串添加前缀意味着使用给定的原始输入
L
LightCC

在 python 3.4 或更高版本中,使用 pathlib.Path

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

.name 属性将给出路径中最后一个子元素的全名,无论它是文件还是文件夹。


3.4 到 3.6 或更高版本,具体取决于您使用的 pathlib 项目。
也可以使用 Path("some/path/to/file.dat").stem 获取不带文件扩展名的文件名
N
Nicolas Gervais
import os
head, tail = os.path.split('path/to/file.exe')

tail 是你想要的,文件名。

详见python os module docs


只是为了让其他用户小心,如果路径以“/”或“\”结尾,则返回“”
S
Saurabh Chandra Patel
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

1
10 Rep

我个人最喜欢的是:

filename = fullname.split(os.sep)[-1]

v
vinu

如果你想自动获取文件名,你可以这样做

import glob

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

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

这将返回:paint.exe

更改有关您的路径或操作系统的拆分函数的 sep 值。


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

在您的示例中,您还需要从右侧去除斜杠以返回 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"
当然,os.path.basename(path) 仅在 os.path.isfile(path)True 时才有效。因此 path = 'a/b/c/' 根本不是一个有效的文件名......
@fmaas os.path.basename 纯粹是一个字符串处理函数。它不关心文件是否存在或者它是文件还是目录。由于尾部斜杠,os.path.basename("a/b/c/") 返回 ""
lazyr 你是对的!我没有想到这一点。只做 path = path.replace('\\', '/') 是否安全?
@Skirmantas 我想,但感觉不对。我认为路径处理应该使用为这项工作制作的内置工具来完成。有 a lot more 的路径比满足眼睛。
C
Csabka

这适用于 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']

S
Santosh kumar Manda

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

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]))

您可以通过检查操作系统类型将两者组合成一个函数并返回结果。


c
crayon

这是工作!

os.path.basename(name)

但是您无法在 Linux 中使用 Windows 文件路径获取文件名。窗户也是。 os.path 在不同的操作系统上加载不同的模块:

Linux - posixpath

Windows - npath

所以你可以使用 os.path 得到正确的结果


请确保您的解决方案尚未在 top one 等其他答案中提出。这些热门问题及其评论中还描述了一些注意事项。
M
Michael Goldshteyn

这是一个仅限正则表达式的解决方案,它似乎适用于任何操作系统上的任何操作系统路径。

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

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/ 是一个目录,c:\windows\ 也是),请将正则表达式更改为: r'[^\\/]+(?![\\/])$' 。对于“受到挑战的正则表达式”,这会将 某种斜线 的正前瞻更改为负前瞻,从而导致以所述 斜杠 结尾的路径名不返回任何内容,而不是路径名中的最后一个子目录。当然,不能保证 potential 文件名实际上是指一个文件,并且需要使用 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

可以测试正则表达式 here


您正在使用 re,为什么不使用 os 模块?
@SaurabhChandraPatel 已经很久了。如果我没记错的话,在这种情况下,正则表达式被用作跨平台解决方案。例如,您可以在 Linux 服务器上处理 windows 文件名。
G
Georgy

也许只是我的多合一解决方案而没有重要的一些新的(关于创建临时文件的临时文件:D)

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

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

无需导入任何模块。


如果文件名或目录包含空格怎么办?
直接 split("/")[-1] 怎么样?
A
Ali Ganjbakhsh

带扩展名的文件名

filepath = './dir/subdir/filename.ext'
basename = os.path.basename(filepath)
print(basename)
# filename.ext

print(type(basename))
# <class 'str'>

不带扩展名的文件名

basename_without_ext = os.path.splitext(os.path.basename(filepath))[0]
print(basename_without_ext)
# filename

G
Gaurav

如果您在一个目录中有许多文件并且想要将这些文件名存储到一个列表中。使用下面的代码。

import os as os
import glob as glob
path = 'mypath'
file_list= []
for file in glob.glob(path):
    data_file_list = os.path.basename(file)
    file_list.append(data_file_list)

P
PythoNic

我从未见过双反斜杠路径,它们存在吗? 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))

这些不是双重反斜杠。它们是单反斜杠,需要转义。
D
David Medenjak

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

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

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])

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

为了完整起见,这里是 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。


g
gaborous

在 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 格式的输入字符串,这对于跨平台比较子路径很有用。


H
HoLengZai

我在 Windows 和 Ubuntu (WSL) 上使用此方法,它仅使用“import os”按预期工作:所以基本上,replace() 根据您当前的操作系统平台放置正确的路径分隔符。

如果路径以斜杠“/”结尾,则它不是文件而是目录,因此它返回一个空字符串。

import os

my_fullpath = r"D:\MY_FOLDER\TEST\20201108\20201108_073751.DNG"
os.path.basename(my_fullpath.replace('\\',os.sep))

my_fullpath = r"/MY_FOLDER/TEST/20201108/20201108_073751.DNG"
os.path.basename(my_fullpath.replace('\\',os.sep))

my_fullpath = r"/MY_FOLDER/TEST/20201108/"
os.path.basename(my_fullpath.replace('\\',os.sep))

my_fullpath = r"/MY_FOLDER/TEST/20201108"
os.path.basename(my_fullpath.replace('\\',os.sep))

https://i.stack.imgur.com/oGJMQ.png