文件有两个关键的属性,一个是“路径”,“路径”指明了文件在计算机中的位置。另一个是“文件名”(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盘是否已经连接到电脑。