无论操作系统或路径格式是什么,我都可以使用哪个 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
实际上,有一个 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.split
或 os.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 文件名,但在编写代码时请记住这一点,以免造成意外的安全漏洞。
os.path
只是在内部加载 ntpath
模块。使用这个模块,即使在 Linux 机器上也可以处理 '\\'
路径分隔符。对于 Linux,posixpath
模块(resp. os.path
)将简化路径操作以仅允许 posix 样式的 '/'
分隔符。
r'C:\path\to\file.txt'
)时,您才需要使用 ntpath 模块。否则,您可以使用 os.path 中的函数。这是因为 Linux 系统通常允许在文件名中使用反斜杠字符(如答案中所述)。
os.path.basename(os.path.normpath(path))
吗?
os.path.split 是您正在寻找的功能
head, tail = os.path.split("/tmp/d/a.dat")
>>> print(tail)
a.dat
>>> print(head)
/tmp/d
在 python 3.4 或更高版本中,使用 pathlib.Path
:
>>> from pathlib import Path
>>> Path("/tmp/d/a.dat").name
'a.dat'
.name
属性将给出路径中最后一个子元素的全名,无论它是文件还是文件夹。
import os
head, tail = os.path.split('path/to/file.exe')
tail 是你想要的,文件名。
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
我个人最喜欢的是:
filename = fullname.split(os.sep)[-1]
如果你想自动获取文件名,你可以这样做
import glob
for f in glob.glob('/your/path/*'):
print(os.path.split(f)[-1])
fname = str("C:\Windows\paint.exe").split('\\')[-1:][0]
这将返回:paint.exe
更改有关您的路径或操作系统的拆分函数的 sep 值。
fname = str(path).split('/')[-1]
在您的示例中,您还需要从右侧去除斜杠以返回 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 路径。
r"a\b\c"
,也不适用于 Windows 上的 "a/b/c"
。
os.path.basename(path)
仅在 os.path.isfile(path)
为 True
时才有效。因此 path = 'a/b/c/'
根本不是一个有效的文件名......
os.path.basename("a/b/c/")
返回 ""
。
lazyr
你是对的!我没有想到这一点。只做 path = path.replace('\\', '/')
是否安全?
这适用于 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']
如果您的文件路径不以“/”结尾且目录以“/”分隔,则使用以下代码。正如我们所知,路径通常不以“/”结尾。
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.path.basename(name)
但是您无法在 Linux 中使用 Windows 文件路径获取文件名。窗户也是。 os.path 在不同的操作系统上加载不同的模块:
Linux - posixpath
Windows - npath
所以你可以使用 os.path 得到正确的结果
这是一个仅限正则表达式的解决方案,它似乎适用于任何操作系统上的任何操作系统路径。
不需要其他模块,也不需要预处理:
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。
也许只是我的多合一解决方案而没有重要的一些新的(关于创建临时文件的临时文件:D)
import tempfile
abc = tempfile.NamedTemporaryFile(dir='/tmp/')
abc.name
abc.name.replace("/", " ").split()[-1]
获取 abc.name
的值将是这样的字符串:'/tmp/tmpks5oksk7'
所以我可以用空格 .replace("/", " ")
替换 /
,然后调用 split()
。这将返回一个列表,我用 [-1]
获得列表的最后一个元素
无需导入任何模块。
带扩展名的文件名
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
如果您在一个目录中有许多文件并且想要将这些文件名存储到一个列表中。使用下面的代码。
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)
我从未见过双反斜杠路径,它们存在吗? 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))
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])
为了完整起见,这里是 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。
在 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 格式的输入字符串,这对于跨平台比较子路径很有用。
我在 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
os.path.basename(your_path)
这行得通!我想要脚本路径:os.path.dirname(os.path.realpath(__file__))
和脚本名称:os.path.basename(os.path.realpath(__file__))
。谢谢!'C:\\temp\\bla.txt'
。