Python文件路径和文件处理
文件有两个关键的属性,一个是“路径”,“路径”指明了文件在计算机中的位置。另一个是“文件名”(filename),“文件名”通常包含基本名称和扩展名。本文着重记录文件路径的处理、文件和文件大小的查看。
1.文件夹之间的分隔符
在windows操作系统上,路径使用倒斜杠(\
)作为文件夹的分隔符,而macos和linux系统则采用正斜杠(/
)。为了是python脚本可以在所有系统上运行,必须处理这两种情况,在python中,pathlib
模块的Path()
函数可以用来处理这种情况,向Path()
函数传入文件夹名称的字符串,Path()
函数即可组合它们。
# 在window系统中
>>> from pathlib import Path
>>> Path('c:/','user','desktop')
WindowsPath('c:/user/desktop') # 虽然windows系统使用倒斜杠,但在交互式环境中WindowsPath使用正斜杠来显示
>>> str(Path('c:/','user','desktop')) # 要单纯获得文本字符串,可以传递给str()来获取
'c:\\user\\desktop'
# 在linux系统中
>>> from pathlib import Path
>>> Path('/home/user','pythonprojects','myproject.py')
PosixPath('/home/user/pythonprojects/myproject.py') # 返回的是PosixPath对象
>>> str(Path('/home/user','pythonprojects','myproject.py'))
'/home/user/pythonprojects/myproject.py'
注意:1.POSIX是针对类UNIX操作系统的一组标准,如Linux,Macos。全称为:可移植操作系统接口(英语:Portable Operating System Interface,缩写为POSIX)。
Python从Python3.4开始引入pathlib
来代替旧的os.path()
函数,python标准库模块从Python3.6开始支持它。
2.使用 /
运算符连接路径
我们可以使用 /
运算符组合Path对象和字符串,这一点在已经使用Path()
函数创建好路径对象后格外有用。
>>> from pathlib import Path
>>> Path('c:/','user','tom','desktop','helloworld.py')
WindowsPath('c:/user/tom/desktop/helloworld.py')
>>> Path('c:/user/tom') / Path('desktop/helloworld.py')
WindowsPath('c:/user/tom/desktop/helloworld.py')
>>> Path('c:/user/tom') / Path('desktop','helloworld.py')
WindowsPath('c:/user/tom/desktop/helloworld.py')
可见,使用Path()
配合 /
处理路径的方式非常灵活容易,如同连接字符串一样。但是相比于使用字符串的连接方法或join()
方法,这种方法更安全,不容易出错。如在windows系统中,使用字符串连接的方法,需要使用转义的\\
,这在移植到类UNIX的系统中会报错。但是Path()
方法会自动处理这些问题。
>>> r'c:\user\al' + '\\' + 'tom'
'c:\\user\\al\\tom'
/ 运算符实际上是替换了较旧的os.path.join()
函数,可以从Python官网查询有关内容。
3.当前工作目录
使用Path.cwd()方法可以获取当前工作目录,该方法替换了较老的os.getcwd()
方法。
>>> from pathlib import Path
>>> import os
>>> Path.cwd() # 获取当前工作目录
WindowsPath('C:/Users/yx')
>>> os.chdir('C:\\Windows\\system32') # 更改工作目录
>>> Path.cwd() # 重新获取,可以发现已经更改
WindowsPath('C:/Windows/system32')
pathlib
不提供更改当前工作目录的函数,因为在程序运行时更改当前工作目录通常会导致一些错误。
4.主目录
主目录是用户在计算机上(windows、linux或macos)存放自己文件的文件夹。可以通过Path.home()
获得主目录的Path对象。
# 在windows中
>>> from pathlib import Path
>>> Path.home()
WindowsPath('C:/Users/yx')
# 在linux中
>>> from pathlib import Path
>>> Path.home()
PosixPath('/home/yuxi')
5.绝对路径和相对路径
绝对路径总是从根文件夹开始。
相对路径是从程序的当前工作目录开始。
.
是当前文件夹的缩写..
是父文件夹的缩写相对路径开始处的
./
是可选的。
6.使用os.makedirs()
创建新文件夹
os.makedirs()
可以一次创建多级文件夹
os.makedirs('C:/Users/mrmx/desktop/folderA/folderB')
使用Path.mkdir()也可以创建文件夹,但是只能创建一级文件夹,方法如下。
>>> Path('C:/Users/yx/desktop/folderC').mkdir() # 在C:/Users/yx/desktop/目录下创建新的folderC文件夹。
显然,不如os.makedirs()
方便。
7.绝对路径和相对路径的处理
Path
对象的is_absolute()
方法可以判断一个路径是否绝对路径,如果返回True
,就是绝对路径,如果返回False
,就是相对路径。
>>> Path('C:/Users/yx/desktop').is_absolute()
True
>>> Path('desktop').is_absolute()
False
要从相对路径获取绝对路径,可以在代表相对路径的Path
对象前加上Path.cwd()/
,因为我们说相对路径,几乎都是相对于当前工作目录来说的。
>>> Path.cwd() / Path('pythonprojects/helloworld.py')
WindowsPath('C:/Users/yx/desktop/pythonprojects/helloworld.py')
当然,如果相对路径是相对于当前工作目录之外的其他路径,只需要把Path.cwd()
改成其他Path对象就可以了。
>>> Path('C:/another_folder') / Path('pythonprojects/helloworld.py')
WindowsPath('C:/another_folder/pythonprojects/helloworld.py')
os.path模块也提供了一些有用的函数用于处理绝对路径和相对路径:
os.path.abspath(path)
,用于返回相对路径的绝对路径os.path.isabs(path)
,用于判断一个路径是否绝对路径os.path.relpath(path,start)
,用于返回从开始路径到path的相对路径的字符串,如果没有提供开始路径,就把当前工作目录作为开始路径
>>> import os
>>> os.path.abspath('.')
'C:\\Users\\yx\\desktop' # 当前工作目录的绝对路径
>>> os.path.abspath('folderA')
'C:\\Users\\yx\\desktop\\folderA' # 同上
>>> os.path.isabs('.')
False
>>> os.path.isabs(os.path.abspath('.'))
True
>>> os.path.relpath('C:\\Users\\yx\\desktop\\folderA','C:\\')
'Users\\yx\\desktop\\folderA' # 从C:\\到C:\\Users\\yx\\desktop\\folderA,使用Users\\yx\\desktop\\folderA可以到达。
>>> os.path.relpath('C:\\Windows','C:\\Users\\yx\\desktop\\folderA')
'..\\..\\..\\..\\Windows' # path和start处于同一个父文件夹(C:\\),就可以使用点点(..)表示法返回到父文件夹。从Users\\yx\\desktop\\folderA到C:\\Windows,使用..\\..\\..\\..\\Windows可以到达。
>>> os.path.relpath('C:\\Windows','E:\\')
Traceback (most recent call last):
File "<python-input-4>", line 1, in <module>
os.path.relpath('C:\\Windows','E:\\')
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "<frozen ntpath>", line 807, in relpath
ValueError: path is on mount 'C:', start on mount 'E:' # 在windows中,跨盘符操作,会提示错误。
8.获取文件路径的各个部分
anchor,drive,parent,name,stem,suffix
上图是Windows系统和macOs/Linux系统的文件路径示意图
锚点(anchor
),是文件系统的根文件夹。
驱动(drive
),在Windows系统中存在,drive属性不包含第一个倒斜杠,是单个字母,(C:,D: 等)。是物理硬盘或U盘、光盘等。
父文件夹(parent
),是包含该文件的文件夹。
文件名(name
),即文件的名字,由基本名称(stem
)和扩展名(suffix
)构成。
# Windows系统
>>> p=Path('C:\\Users\\yx\\desktop\\folderA\\helloworld.py')
>>> p.anchor
'C:\\'
>>> p.drive
'C:'
>>> p.parent
WindowsPath('C:/Users/yx/desktop/folderA')
>>> p.name
'helloworld.py'
>>> p.stem
'helloworld'
>>> p.suffix
'.py'
# Linux系统
>>> p = Path('/home/yuxi/helloworld.py')
>>> p.anchor
'/'
>>> p.parent
PosixPath('/home/yuxi')
>>> p.name
'helloworld.py'
>>> p.stem
'helloworld'
>>> p.suffix
'.py'
>>> p.drive
'' # Linux系统没有drive属性
以上属性,除了parent
是一个Path
对象,其它都是字符串。
parents属性
parents属性返回的是一组Path对象,代表祖先文件夹,具有整数索引。
>>> parents = p.parents
>>> parents
<WindowsPath.parents>
>>> parents[0]
WindowsPath('C:/Users/yx/desktop/folderA')
>>> parents[1]
WindowsPath('C:/Users/yx/desktop')
>>> parents[2]
WindowsPath('C:/Users/yx')
>>> parents[3]
WindowsPath('C:/Users')
>>> parents[4]
WindowsPath('C:/')
>>> for parent in parents:
... print(parent)
...
C:\Users\yx\desktop\folderA
C:\Users\yx\desktop
C:\Users\yx
C:\Users
C:\
>>>
较老的os.path模块中的类似函数
os.path.basename()
获取最后一个斜杠后的内容,类似于文件名(当然如果最后一级是文件夹,那就是文件夹);
os.path.dirname()
获取最后一个斜杠之前的内容。
os.path.split()
可以把二者分开,返回一个由前二者组成的元组。
>>> file_path = 'C:/Users/yx/desktop/folderA/helloworld.py'
>>> file_path2 = 'C:/Users/yx/desktop/folderA'
>>> os.path.basename(file_path)
'helloworld.py'
>>> os.path.basename(file_path2)
'folderA'
>>> os.path.dirname(file_path)
'C:/Users/yx/desktop/folderA'
>>> os.path.dirname(file_path2)
'C:/Users/yx/desktop'
>>> os.path.split(file_path)
('C:/Users/yx/desktop/folderA', 'helloworld.py')
>>> os.path.split(file_path2)
('C:/Users/yx/desktop', 'folderA')
如果要获取一个路径上的每个文件夹(文件)字符串的列表,可以使用split()字符串方法,配合os.sep
进行分割。
>>> path = 'C:\\Users\\yx\\desktop\\folderA\\helloworld.py'
>>> path.split(os.sep)
['C:', 'Users', 'yx', 'desktop', 'folderA', 'helloworld.py']
os.sep被设置为正确的目录分割斜杠,Windows中'\\
',macOS和Linux中‘/
’,所以下面的例子中无法返回上例的结果。
# Windows
>>> file_path = 'C:/Users/yx/desktop/folderA/helloworld.py' # windows系统中使用 / 分割
>>> file_path.split(os.sep)
['C:/Users/yx/desktop/folderA/helloworld.py']
另外,在macOS和Linux中,列表开始会有一个空字符串:
>>> p = '/home/yuxi/helloworld.py'
>>> p.split(os.sep)
['', 'home', 'yuxi', 'helloworld.py']
9.查看文件大小和文件夹内容
有办法处理文件路径,就可以搜集特定的文件和文件夹的信息了。
os.path.getsize(path)
,可以返回指定path中文件的字节数(大小)。os.listdir(path)
,可以返回指定path中文件名的字符串列表(内容)。
注意:不是os.path.listdir
>>> os.path.getsize('C:/Users/yx/desktop/folderA/helloworld.py')
21
>>> os.listdir('C:/Users/yx/desktop/folderA')
['folderB', 'helloworld.py']
>>> path = Path('C:/Windows')
>>> for file in os.listdir('C:/Windows'):
... print(f'{file}大小:{os.path.getsize(path / file)}')
...
.soft大小:0
addins大小:0
appcompat大小:4096
apppatch大小:4096
AppReadiness大小:0
assembly大小:4096
bcastdvr大小:0
bfsvc.exe大小:126976
Boot大小:4096
bootstat.dat大小:67584
Branding大小:0
BrowserCore大小:0
CbsTemp大小:0
Containers大小:0
CSC大小:0
Cursors大小:32768
debug大小:0
diagnostics大小:0
DiagTrack大小:4096
DigitalLocker大小:0
Downloaded Program Files大小:0
ELAMBKUP大小:0
en-US大小:4096
explorer.exe大小:3038464
Fonts大小:98304
10.使用通配符模式修改文件列表(Path.glob()
)
如果要处理特定的文件,Path
对象的glob()
方法要比os.listdir()
更简单一些。glob()
方法返回一个生成器对象,将它传递给list()
可以查看。
>>> p = Path('C:/Windows')
>>> p.glob('*')
<map object at 0x0000013A8B3D5FF0>
>>> list(p.glob('*'))
[WindowsPath('C:/Windows/.soft'), WindowsPath('C:/Windows/addins'), WindowsPath('C:/Windows/appcompat'), WindowsPath('C:/Windows/apppatch'), WindowsPath('C:/Windows/AppReadiness'), WindowsPath('C:/Windows/assembly'), WindowsPath('C:/Windows/bcastdvr'), WindowsPath('C:/Windows/bfsvc.exe'), WindowsPath('C:/Windows/Boot'), WindowsPath('C:/Windows/bootstat.dat'), WindowsPath('C:/Windows/Branding'), WindowsPath('C:/Windows/BrowserCore'), WindowsPath('C:/Windows/CbsTemp'), WindowsPath('C:/Windows/Containers'), WindowsPath('C:/Windows/CSC'), WindowsPath('C:/Windows/Cursors'), WindowsPath('C:/Windows/debug'), WindowsPath('C:/Windows/diagnostics'), WindowsPath('C:/Windows/DiagTrack'), WindowsPath('C:/Windows/DigitalLocker'), WindowsPath('C:/Windows/Downloaded Program Files'), WindowsPath('C:/Windows/ELAMBKUP'), WindowsPath('C:/Windows/en-US'), WindowsPath('C:/Windows/explorer.exe'), WindowsPath('C:/Windows/Fonts'), WindowsPath('C:/Windows/GameBarPresenceWriter'), WindowsPath('C:/Windows/Globalization'), WindowsPath('C:/Windows/Help'), WindowsPath('C:/Windows/HelpPane.exe'), WindowsPath('C:/Windows/hh.exe'), WindowsPath('C:/Windows/IdentityCRL'), WindowsPath('C:/Windows/IME'), WindowsPath('C:/Windows/ImmersiveControlPanel'), WindowsPath('C:/Windows/InboxApps'), WindowsPath('C:/Windows/INF'), WindowsPath('C:/Windows/Info.xml'), WindowsPath('C:/Windows/InputMethod'), WindowsPath('C:/Windows/Installer'), WindowsPath('C:/Windows/L2Schemas'), WindowsPath('C:/Windows/LanguageOverlayCache'), WindowsPath('C:/Windows/LiveKernelReports'), WindowsPath('C:/Windows/Logs'), WindowsPath('C:/Windows/Media'), WindowsPath('C:/Windows/mib.bin'), WindowsPath('C:/Windows/Microsoft'), WindowsPath('C:/Windows/Microsoft.NET'), WindowsPath('C:/Windows/Migration'), WindowsPath('C:/Windows/ModemLogs'), WindowsPath('C:/Windows/notepad.exe'), WindowsPath('C:/Windows/OCR'), WindowsPath('C:/Windows/Offline Web Pages'), WindowsPath('C:/Windows/Panther'), WindowsPath('C:/Windows/Performance'), WindowsPath('C:/Windows/PLA'), WindowsPath('C:/Windows/PolicyDefinitions'), WindowsPath('C:/Windows/popcinfot.dat'), WindowsPath('C:/Windows/Prefetch'), WindowsPath('C:/Windows/Professional.xml'), WindowsPath('C:/Windows/Provisioning'), WindowsPath('C:/Windows/py.exe'), WindowsPath('C:/Windows/pyshellext.amd64.dll'), WindowsPath('C:/Windows/pyw.exe'), WindowsPath('C:/Windows/regedit.exe'), WindowsPath('C:/Windows/Registration'), WindowsPath('C:/Windows/RemotePackages'), WindowsPath('C:/Windows/rescache'), WindowsPath('C:/Windows/Resources'), WindowsPath('C:/Windows/SchCache'), WindowsPath('C:/Windows/schemas'), WindowsPath('C:/Windows/security'), WindowsPath('C:/Windows/ServiceProfiles'), WindowsPath('C:/Windows/ServiceState'), WindowsPath('C:/Windows/servicing'), WindowsPath('C:/Windows/Setup'), WindowsPath('C:/Windows/setupact.log'), WindowsPath('C:/Windows/setuperr.log'), WindowsPath('C:/Windows/ShellComponents'), WindowsPath('C:/Windows/ShellExperiences'), WindowsPath('C:/Windows/SHELLNEW'), WindowsPath('C:/Windows/SKB'), WindowsPath('C:/Windows/SoftwareDistribution'), WindowsPath('C:/Windows/Speech'), WindowsPath('C:/Windows/Speech_OneCore'), WindowsPath('C:/Windows/splwow64.exe'), WindowsPath('C:/Windows/System'), WindowsPath('C:/Windows/system.ini'), WindowsPath('C:/Windows/System32'), WindowsPath('C:/Windows/SystemApps'), WindowsPath('C:/Windows/SystemResources'), WindowsPath('C:/Windows/SystemTemp'), WindowsPath('C:/Windows/SysWOW64'), WindowsPath('C:/Windows/TAPI'), WindowsPath('C:/Windows/Tasks'), WindowsPath('C:/Windows/Temp'), WindowsPath('C:/Windows/TextInput'), WindowsPath('C:/Windows/TMP'), WindowsPath('C:/Windows/tracing'), WindowsPath('C:/Windows/twain_32'), WindowsPath('C:/Windows/twain_32.dll'), WindowsPath('C:/Windows/UUS'), WindowsPath('C:/Windows/Vss'), WindowsPath('C:/Windows/WaaS'), WindowsPath('C:/Windows/Web'), WindowsPath('C:/Windows/win.ini'), WindowsPath('C:/Windows/WindowsShell.Manifest'), WindowsPath('C:/Windows/WindowsUpdate.log'), WindowsPath('C:/Windows/winhlp32.exe'), WindowsPath('C:/Windows/WinSxS'), WindowsPath('C:/Windows/WMSysPr9.prx'), WindowsPath('C:/Windows/WUModels'), WindowsPath('C:/Windows/zh-CN')]
星号(*)代表多个任意字符,因此,上例返回了目录下的所有文件。
类似于正则表达式,可以传递给glob()更多的表达式:
>>> list(p.glob('*.exe')) # 后缀名是.exe的文件
[WindowsPath('C:/Windows/bfsvc.exe'), WindowsPath('C:/Windows/explorer.exe'), WindowsPath('C:/Windows/HelpPane.exe'), WindowsPath('C:/Windows/hh.exe'), WindowsPath('C:/Windows/notepad.exe'), WindowsPath('C:/Windows/py.exe'), WindowsPath('C:/Windows/pyw.exe'), WindowsPath('C:/Windows/regedit.exe'), WindowsPath('C:/Windows/splwow64.exe'), WindowsPath('C:/Windows/winhlp32.exe')]
>>> list(p.glob('explore?.exe')) # ?代表一个字符
[WindowsPath('C:/Windows/explorer.exe')]
>>> list(p.glob('*.?x?')) # 任意名称,后缀名三个字符其中中间字符是x的文件
[WindowsPath('C:/Windows/bfsvc.exe'), WindowsPath('C:/Windows/explorer.exe'), WindowsPath('C:/Windows/HelpPane.exe'), WindowsPath('C:/Windows/hh.exe'), WindowsPath('C:/Windows/notepad.exe'), WindowsPath('C:/Windows/py.exe'), WindowsPath('C:/Windows/pyw.exe'), WindowsPath('C:/Windows/regedit.exe'), WindowsPath('C:/Windows/splwow64.exe'), WindowsPath('C:/Windows/winhlp32.exe')]
当然,既然是生成器对象,也可以用for来遍历:
>>> for _ in p.glob('*.?x?'):
... print(_) # print出来的是字符串的形式,不带WindowsPath
...
C:\Windows\bfsvc.exe
C:\Windows\explorer.exe
C:\Windows\HelpPane.exe
C:\Windows\hh.exe
C:\Windows\notepad.exe
C:\Windows\py.exe
C:\Windows\pyw.exe
C:\Windows\regedit.exe
C:\Windows\splwow64.exe
C:\Windows\winhlp32.exe
11.检查路径的有效性
如果提供的路径不存在,Python可能会在运行时报错,Path对象有一些方法可以检查路径的有效性:
假定p是一个Path对象,
p.exists()
,路径是否存在,返回True或False,
p.is_file()
,路径存在且是一个文件,返回True或False,
p.is_dir()
,路径存在且是一个文件夹,返回True或False。
# Windows 有文件结构如下
>>> os.listdir(Path.cwd())
['folderB', 'helloworld.py']
>>> exists_dir =Path('C:/Users/yx/desktop/folderA/folderB')
>>> none_exists_dir = Path('C:/Users/yx/desktop/NoneExistsFolder')
>>> exists_file = Path('C:/Users/yx/desktop/folderA/helloworld.py')
>>> none_exists_file = Path('C:/Users/yx/desktop/folderA/NoneExistsFile.py')
# 对存在的文件夹进行验证
>>> exists_dir.exists()
True
>>> exists_dir.is_dir()
True
>>> exists_dir.is_file()
False
# 对不存在的文件夹进行验证
>>> none_exists_dir.exists()
False
>>> none_exists_dir.is_dir()
False
>>> none_exists_dir.is_file()
False
# 对存在的文件进行验证
>>> exists_file.exists()
True
>>> exists_file.is_dir()
False
>>> exists_file.is_file()
True
# 对不能存在的文件进行验证
>>> none_exists_file.exists()
False
>>> none_exists_file.is_dir()
False
>>> none_exists_file.is_file()
False
较老的os.path
模块提供有os.path.exists(path)
, os.path.isfile(path)
, os.path.isdir(path)
,可以完成相同的任务。
好了,现在我们就可以判断某个文件或文件夹是否存在了。常见的,我们可以用来验证某个光盘或U盘是否已经连接到电脑。
- 感谢你赐予我前进的力量