你好,游客 登录 注册 搜索
背景:
阅读新闻

Python之文件与目录操作(os、zipfile、tarfile、shutil)

[日期:2017-05-28] 来源:Linux社区  作者:yyds [字体: ]

Python中可以用于对文件和目录进行操作的内置模块包括:

模块/函数名称功能描述
open()函数 文件读取或写入
os.path模块 文件路径操作
os模块 文件和目录简单操作
zipfile模块 文件压缩
tarfile模块 文件归档压缩
shutil模块 高级文件和目录处理及归档压缩
fileinput模块 读取一个或多个文件中的所有行
tempfile模块 创建临时文件和目录

其中文件读取或写入已经在之前的文章中进行了描述,具体请参考这里 <。这里主要对其它几个模块进行下说明。

一、文件路径操作(os.path模块)


os.path模块主要用于对文件路径的操作,如:路径分割和拼接、取文件相对路径和绝对路径、获取文件路径对应文件的时间属性、判断文件路径对应文件的类型、判断两个路径是否为同一个文件等。

1. 函数列表

# 返回指定文件的绝对路径名
os.path.abspath(path)

# 将路径名称分割成两部分(head, tail),tail是路径名称path中的最后一部分且不包含斜线(路径风格符),head是tail之前的所有部分;如果path以斜线结尾则 tail为空字符串,如果path中没有斜线则head为空字符串
os.path.split(path)

# 将路径名称分割成两部分(root, ext), ext表示后缀名
os.path.splitext(path)  

# 返回path路径名的基名称,实际上就是os.path.split(path)函数返回值的第二个值
os.path.basename(path)  

# 返回path路径名的目录名称,实际上就是os.path.split(path)函数返回值的第一个值
os.path.dirname(path)  

# 将一个或多个路径中的非空值通过路径分隔符拼接成一个新的路径名称,如果在拼接过程中遇到绝对路径将会丢弃前面的部分并从该绝对路径重新开始拼接
os.path.join(path, *paths)  

# 指定的文件路径存在则返回Ture,否则返回False。如果是失效的链接文件则返回False
os.path.exists(path)  

# 返回该路径对应文件的最近一次访问时间的时间戳(秒),如果文件不存在或无法访问,则引发OSError
os.path.getatime(path)  

# 返回该路径对应文件的最后修改时间的时间戳(秒),如果文件不存在或无法访问,则引发OSError
os.path.getmtime(path)  

# 返回该路径对应文件的ctime,在某些系统上(如Unix上)是最后一次元数据更改时间,在其他系统上(如Windows)是路径的创建时间;如果文件不存在或无法访问,则引发OSError
os.path.getctime(path)  

# 返回指定路径对应文件的字节大小
os.path.getsize(path)  

# 返回path相对于start的相对路径
os.path.relpath(path, start=os.curdir)  

# 获取path的真实、绝对路径(可用于获取软链接文件指向的文件路径)
os.path.realpath(path)  

# 判断path是否是绝对路径,是则返回True,否则返回False
os.path.isabs(path)  

# 判断path是否是一个文件
os.path.isfile(path)  

# 判断path是否是一个目录
os.path.isdir(path) 

# 判断path是否是一个链接
os.path.islink(path)  

# 判断path是否是一个挂载点
os.path.ismount(path)  

# 判断path1和path2是否为同一个文件
os.path.samefile(path1, path2)  

注意: os.path.basename(path)函数与Unix 中的basename程序的不同之处在于,当path以路径分隔符结尾时(如'/usr/local/'),basename(path)返回值为空字符串(''),而basename程序返回值为倒数第二个路径分隔符之后的目录名称('local')

2. 实例

>>> import os
>>> 
>>> os.path.abspath('test.sh')
'/root/test.sh'

>>> os.path.split('/root/test.sh')
('/root', 'test.sh')
>>> os.path.split('/usr/local')
('/usr', 'local')
>>> os.path.split('/usr/local/')
('/usr/local', '')
>>> os.path.split('test.sh')
('', 'test.sh')

>>> os.path.basename('/root/test.sh')
'test.sh'
>>> os.path.dirname('/root/test.sh')
'/root'

>>> os.path.splitext('test.sh')
('test', '.sh')
>>> os.path.splitext('/root/test.sh')
('/root/test', '.sh')
>>> os.path.splitext('/usrl/local')
('/usrl/local', '')

>>> os.path.join('/root')
'/root'
>>> os.path.join('/root', '1', '', '2', ' ', '3' )
'/root/1/2/ /3'
>>> os.path.join('/root', '/usr/local', 'test.sh')
'/usr/local/test.sh'
>>> os.path.join('/root', '/usr/local', '1', '')
'/usr/local/1/'

>>> os.path.exists('/root/test.sh')
True
>>> os.path.exists('/root/test.txt')
False
>>> os.path.exists('/etc/rc0.d')
True

>>> os.path.getatime('/etc/my.cnf')
1483433424.62325
>>> os.path.getmtime('/etc/my.cnf')
1472825145.4308648
>>> os.path.getctime('/etc/my.cnf')
1472825145.432865

>>> os.path.relpath('/etc/my.cnf')
'../etc/my.cnf'
>>> os.path.relpath('/etc/my.cnf', start='/etc')
'my.cnf

>>> os.path.realpath('/etc/rc0.d')
'/etc/rc.d/rc0.d'
>>> os.path.realpath('test.sh')
'/root/test.sh'

>>> os.system('ls -l /etc/my.cnf')
-rw-r--r-- 1 root root 597 Sep  2 22:05 /etc/my.cnf
>>> os.path.getsize('/etc/my.cnf')
597

>>> os.path.isabs('/etc/my.cnf')
True
>>> os.path.isabs('my.cnf')
False
>>> os.path.isfile('/etc/my.cnf')
True
>>> os.path.isdir('/etc/my.cnf')
False
>>> os.path.islink('/etc/my.cnf')
False
>>> os.path.islink('/etc/rc0.d')
True
>>> os.path.islink('/etc/rc0.d/')
False
>>> os.path.isdir('/etc/rc0.d/')
True
>>> os.path.isdir('/etc/rc0.d')
True

>>> os.system('df -Th')
Filesystem     Type      Size  Used Avail Use% Mounted on
/dev/vda1      ext4       40G  8.7G   29G  24% /
devtmpfs       devtmpfs  3.9G     0  3.9G   0% /dev
tmpfs          tmpfs     3.9G     0  3.9G   0% /dev/shm
tmpfs          tmpfs     3.9G  401M  3.5G  11% /run
tmpfs          tmpfs     3.9G     0  3.9G   0% /sys/fs/cgroup
tmpfs          tmpfs     783M     0  783M   0% /run/user/0
0
>>> os.path.ismount('/')
True
>>> os.path.ismount('/dev')
True
>>> os.path.ismount('/usr')
False

>>> os.path.samefile('/etc/rc0.d', '/etc/rc0.d')
True
>>> os.path.samefile('/etc/rc0.d', '/etc/rc0.d/')
True

二、文件及目录操作(os模块)


需要说明的是: os模块是一个混杂的操作系统接口模块,它提供了各种操作系统相关的功能,文件及目录操作只是其中一部分,而非全部。

在一些Unix平台上,这个模块的许多文件或目录的操作函数都支持下面的一个或多个特性:

  • 指定一个文件描述符 对于某些函数,path参数不仅仅可以是一个字符串,还可以是一个文件描述符。该函数会操作这个文件描述符引用的文件。我们可以通过os.supports_fd来检查当前平台path参数是否可以指定为一个文件描述符,如果不可用将会引发一个NotImplementedError。如果该函数还支持dir_fd或follow_symlinks参数,当path被以文件描述符的方式提供时,指定dir_fd或follow_symlinks参数是错误的。
  • 相对于目录描述符的路径 如果dir_fd不是None,它应该是一个指向某个目录的文件描述符,并且要操作的path应该是一个相对于该目录的相对路径;如果path是一个绝对路径,dir_fd将会被忽略。
  • 不遵循符号链接 如果follow_symlinks是False,并且要操作的路径中最后一个元素是一个符号链接时,该函数将会操作这个链接文件,而不是操作这个链接文件指向的文件。

1. 相关方法列表

# 测试当前用户是否对path所对应文件有某种访问权限
# Python2
os.access(path, mode)
# Python3
os.access(path, mode, *, dir_fd=None, effective_ids=False, follow_symlinks=True)

# 更改当前工作目录,从Python3.3开始path参数允许是一个目录的文件描述符
os.chdir(path)

# 更改当前工作目录,从Python3.3开始该函数等价于os.chdir(fd)
os.chfdir(fd)

# 更改文件或目录权限,dir_fd和follow_symlinks是Python3.3新增的参数
os.chmod(path, mode, *, dir_fd=None, follow_symlinks=True)

# 更改文件或目录权限,如果path是个链接文件则影响是链接文件本身;Python3.3开始该函数等价于os.chmod(path, mode, follow_symlinks=False)
os.lchmod(path, mode)

# 更改文件或目录的属主和属组,如果不改变则设置为-1;dir_fd和follow_symlinks是Python3.3新增的参数
os.chown(path, uid, gid, *, dir_fd=None, follow_symlinks=True)

# 更改文件或目录的属主和属组,如果不改变则设置为-1;如果path是个链接文件则影响是链接文件本身;Python3.3开始该函数等价于os.chown(path, uid, gid, follow_symlinks=False)
os.lchown(path, uid, gid)

# 更改当前进程主目录
os.chroot(path)

# 返回一个表示当前目录的字符串
os.getcwd()

# 返回一个表示当前目录的字节串,Python3新添加的函数
os.getcwdb()

# 创建硬链接, *后面的参数都是Python3.3新增的
os.link(src, dst, *, src_dir_fd=None, dst_dir_fd=None, follow_symlinks=True)

# 创建软链接,*后面的参数都是Python3.3新增的
os.symlink(src, dst, target_is_directory=False, * dir_fd=None)

# 返回指定目录中所有文件列表,顺序不固定,且不包含‘.’和‘..’;注意path在Python2中没有默认值
os.listdir(path='.')

# 返回指定目录中所有文件条目对应的DirEntry对象迭代器,顺序不固定,则不包含'.'和‘..’;Python3.5新增的函数
os.scandir(path='.')

# 获取文件或文件描述的状态信息,染回一个stat_result对象,dir_fd和follow_symlinks都是Python3.3新增的参数
os.stat(path, *, dir_fd=None, follow_symlinks=True)

# 获取文件或文件描述的状态信息,如果path是一个链接文件则获取的是链接文件本身的状态信息;Python3.3开始,该函数等价于os.stat(path, dir_fd=dir_fd, folow_symlinks=False)
os.lstat(path, *, dir_fd=None)

# 创建一个名为path的目录并指定目录权限,如果目录已经存在则会引起FileExistsError;dir_fd是Python3.3开始新加的参数。需要说明的是该函数与os.makedirs()、os.mkfifo()函数创建的目或逛到文件的权限会受到umask的影响,比如指定mode为0777,实际目录权限为 0777 - umask = 0755
os.mkdir(path, mode=0o777, *, dir_fd=None)

# 递归创建目录,该函数功能与mkdir()相似,但是会递归创建所有的中间目录;exist_ok为Python3.2新增参数,表示当目录已经存在时是否正常返回,如果exist_ok为False(默认)且目标目录已经存在则会引发OSError
os.makedirs(name, mode=0o777, exists_ok=False)

# 创建一个FIFO(命名管道)文件,FIFO可以被当做正常文件那样访问;通常FIFOs被用作‘client’和‘server’类型进程的汇集点,server打开FIFO读取数据,client打开FIFO写入数据。
os.mkfifo(path, mode=0o666, *, dir_fd=None)

# 删除指定的文件,如果path是个目录将会引发OSError
os.remove(path, *, dir_fd=None)
os.unlink(path, *, dir_fd=None)

# 删除指定的空目录,如果目录不为空会引发OSError
os.rmdir(path, *, dir_fd=None)

# 递归删除指定路径中的所有空目录
os.removedirs(name)

# 目录或文件重命名,如果dst是一个目录见鬼引发OSError。在Unix平台上,如果dst存在且是一个文件,那么只要用户有权限就将会被静默替换;而在Windows平台上,如果dst存在,即使它是一个文件也会引发OSError
os.rename(src, dst, *, src_dir_fd=-None, dst_dir_fd=None)

# 目录或文件递归重命名
os.renames(old, new)

# 与os.rename()功能相同,区别在于:对于os.replace()来说,如果dst存在且是一个文件,那么只要用户有权限就将会被静默替换,而没有平台上的差别
os.replace(src, dst, *, src_dir_fd=None, dst_dir_fd=None)

# 返回链接文件指向的真实路径,类似于os.path.relpath(path),但是该方法可能返回相对路径
os.readlink(path, *, dir_fd=None)

# 返回一个文件的某个系统配置信息,name表示配置项名称,可以通过os.pathconf_names来查看可用的值
os.pathconf(path, name)

关于os.access()函数的说明:默认以用户的真实uid(RUID)和gid来对文件的访问权限做检测,但是大部分操作将会使用有效uid(EUID)或gid去做检测,且Python3中可以通过将effective_ids参数设置为Ture来使用有效uid/gid来做权限检测(关于RUID/EUID/SUID的概念可以参考<<这篇文章>>
)。mode可取值为:os.F_OK(文件存在)、os.R_OK(可读)、os.W_OK(可写)、os.X_OK(可执行)中的一个或用逻辑运算符连接起来的多个。

2. 实例

>>> import os
>>> 
>>> os.access('/bin/passwd', os.F_OK)
True
>>> os.access('/bin/passwd', os.F_OK|os.X_OK)
True
>>> os.access('/bin/passwd', os.F_OK|os.W_OK)
True

>>> os.getcwd()
'/root'
>>> os.chdir('/tmp')
>>> os.getcwd()
'/tmp'

>>> os.system('ls -l test*')
-rw-r--r-- 1 root root 0 Feb  9 09:02 test1.txt
lrwxrwxrwx 1 root root 9 Feb  9 09:02 test.txt -> test1.txt
0
>>> os.chmod('/tmp/test.txt', 0666)
>>> os.system('ls -l test*')
-rw-rw-rw- 1 root root 0 Feb  9 09:02 test1.txt
lrwxrwxrwx 1 root root 9 Feb  9 09:02 test.txt -> test1.txt
0

>>> os.link('test.txt', 'test')
>>> os.system('ls -li test*')
271425 lrwxrwxrwx 2 root  root  9 Feb  9 09:02 test -> test1.txt
271379 -rw-rw-rw- 1 mysql mysql 0 Feb  9 09:02 test1.txt
271425 lrwxrwxrwx 2 root  root  9 Feb  9 09:02 test.txt -> test1.txt
0

>>> os.listdir('.')
['zabbix_proxy.log', 'test.txt', 'zabbix_agentd.log', '.Test-unix', 'systemd-private-14bb029ad4f340d5ac49a6fb3c2ca6c9-systemd-machined.service-gJk0Cd', 'hsperfdata_root', 'wrapper-31124-1-out', 'a', 'test1.txt', 'zabbix_proxy.log.old', 'zabbix_agentd.log.old', 'systemd-private-14bb029ad4f340d5ac49a6fb3c2ca6c9-mariadb.service-kudcMu', 'test', '.X11-unix', '.font-unix', 'wrapper-31124-1-in', '.XIM-unix', '.ICE-unix', 'Aegis-<Guid(5A2C30A2-A87D-490A-9281-6765EDAD7CBA)>']
>>> os.listdir('/tmp')
['zabbix_proxy.log', 'test.txt', 'zabbix_agentd.log', '.Test-unix', 'systemd-private-14bb029ad4f340d5ac49a6fb3c2ca6c9-systemd-machined.service-gJk0Cd', 'hsperfdata_root', 'wrapper-31124-1-out', 'a', 'test1.txt', 'zabbix_proxy.log.old', 'zabbix_agentd.log.old', 'systemd-private-14bb029ad4f340d5ac49a6fb3c2ca6c9-mariadb.service-kudcMu', 'test', '.X11-unix', '.font-unix', 'wrapper-31124-1-in', '.XIM-unix', '.ICE-unix', 'Aegis-<Guid(5A2C30A2-A87D-490A-9281-6765EDAD7CBA)>']

>>> os.mkdir('/tmp/testdir')
>>> os.system('ls -l /tmp')
lrwxrwxrwx 2 root   root         9 Feb  9 09:02 test -> test1.txt
-rw-rw-rw- 1 mysql  mysql        0 Feb  9 09:02 test1.txt
drwxr-xr-x 2 root   root      4096 Feb  9 09:47 testdir
lrwxrwxrwx 2 root   root         9 Feb  9 09:02 test.txt -> test1.txt
>>> os.mkdir('/tmp/testdir')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 17] File exists: '/tmp/testdir'
>>> os.mkdir('/tmp/a/b/c')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 2] No such file or directory: '/tmp/a/b/c'
>>> os.makedirs('/tmp/a/b/c')  # mode默认为0777,结果却是0755,bug?
>>> os.makedirs('/tmp/b/c/d', 0700)
>>> os.system('ls -l /tmp')
total 2316
drwxr-xr-x 3 root   root      4096 Feb  9 10:16 a
drwx------ 3 root   root      4096 Feb  9 10:16 b
lrwxrwxrwx 2 root   root         9 Feb  9 09:02 test -> test1.txt
-rw-rw-rw- 1 mysql  mysql        0 Feb  9 09:02 test1.txt
drwxr-xr-x 2 root   root      4096 Feb  9 09:47 testdir
lrwxrwxrwx 2 root   root         9 Feb  9 09:02 test.txt -> test1.txt

>>> os.rename('/tmp/test1.txt', '/tmp/test3.txt')
>>> os.system('ls -l /tmp')
lrwxrwxrwx 2 root   root         9 Feb  9 09:02 test -> test1.txt
prw-r--r-- 1 root   root         0 Feb  9 10:21 test1.fifo
-rw-rw-rw- 1 mysql  mysql        0 Feb  9 09:02 test3.txt
drwxr-xr-x 2 root   root      4096 Feb  9 09:47 testdir
prw-r--r-- 1 root   root         0 Feb  9 10:20 test.fifo
lrwxrwxrwx 2 root   root         9 Feb  9 09:02 test.txt -> test1.txt

>>> os.readlink('/tmp/test.txt')
'test1.txt'

>>> os.rmdir('/tmp/testdir')
>>> os.rmdir('/tmp/a/b/c')  # 只删除空目录/tmp/a/b/c
>>> os.removedirs('/tmp/b/c/d')  # 先删除空目录/tmp/a/b/c,然后删除空目录/tmp/a/b,最后删除目录/tmp/a,而目录/tmp非空,因此不会被删除

>>> os.unlink('/tmp/test')
>>> os.unlink('/tmp/test.fifo')
>>> os.unlink('/tmp/test.txt')
>>> os.system('ls -l /tmp')
>>> os.remove('/tmp/test3.txt')
>>> os.remove('/tmp/test1.fifo')

三、文件压缩(zipfile模块)


1. zipfile模块包含的类

顾名思义,zipfile模块用于文件的压缩操作,该模块包含以下几个类:

类名描述
zipfile.ZipFile 用于ZIP文件的读写操作
zipfile.PyZipFile 用于创建包含Python库的ZIP归档文件
zipfile.ZipInfo 用于表示归档文件中的一个成员信息

zipfile.ZipInfo类的实例可以通过ZipFile对象的getinfo()和infolist()方法获取。

2. zipfile模块中的函数和常量

函数/常量名描述
zipfile.is_zipfile(filename) 判断filename是否是一个有效的ZIP文件,并返回一个布尔类型的值
zipfile.ZIP_STORED 表示一个压缩的归档成员
zipfile.ZIP_DEFLATED 表示普通的ZIP压缩方法,需要zlib模块的支持
zipfile.ZIP_BZIP2 表示BZIP2压缩方法,需要bz2模块的支持;Python3.3新增
zipfile.ZIP_LZMA 表示LZMA压缩方法,需要lzma模块的支持;Python3.3新增

3. zipfile.ZipFile类

类的构造方法

class zipfile.ZipFile(file, mode='r', compression=ZIP_STORED, allowZip64=True)

创建一个ZipFile实例,表示打开一个ZIP文件。

参数:

  • file:可以是一个文件的路径(字符串),也可以是一个file-like对象;
  • mode:表示文件代开模式,可取值有:r(读), w(写), a(添加), x(创建和写一个唯一的新文件,如果文件已存在会引发FileExistsError)
  • compression:表示对归档文件进行写操作时使用的ZIP压缩方法,可取值有:ZIP_STORED, ZIP_DEFLATED, ZIP_BZIP2, ZIP_LZMA, 传递其他无法识别的值将会引起RuntimeError;如果取ZIP_DEFLATED, ZIP_BZIP2, ZIP_LZMA,但是相应的模块(zlib, bz2, lzma)不可用,也会引起RuntimeError;
  • allowZip64:如若zipfile大小超过2GiB且allowZip64的值为False,则将会引起一个异常

说明:

  • 从Python 3.2开始支持使用ZipFile作为上下文管理器(with语法)
  • 从Python 3.3开始支持bzip2和lzma压缩
  • 从Python 3.4开始allowZip64默认值改为True
  • 从Python 3.5开始添加对unseekable streams的写操作支持以及对‘x’ mode的支持

实例方法列表

# 打印该归档文件的内容
printdir()

# 从归档文件中展开一个成员到当前工作目录,memeber必须是一个完整的文件名称或者ZipInfo对象,path可以用来指定一个不同的展开目录,pwd用于加密文件的密码
extract(memeber, path=None, pwd=None)

# 从归档文件展开所有成员到当前工作目录,path和pwd参数作用同上,memebers必须是namelist()返回的list的一个子集
extractall(path=None, members=None, pwd=None)

# 返回一个与每一个归档成员对应的ZipInfo对象的列表
infolist()

# 返回归档成员名称列表
namelist()

# 返回一个包含压缩成员name相关信息的ZipInfo对象,如果name没有被包含在该压缩文档中将会引发KeyError
getinfo(name)

# 将归档文件中的一个成员作为一个file-like对象展开;name是归档文件中的文件名或者一个ZipInfo对象
open(name, mode='r', pwd=None)

# 关闭该压缩文件;退出程序前必须调用close()方法,否则一些必要记录不会被写入
close()

# 设置pwd作为展开加密文件的默认密码
setpassword(pwd)

# 读取归档文件中所有文件并检查它们的完整性,返回第一个被损坏的文件名称,或者None。对已关闭的ZipFile调用testzip()将会引发RuntimeError
testzip()

# 返回归档文件中name所指定的成员文件的字节。name是归档文件中的文件名称或一个ZipInfo对象。该归档文件必须以读(r)或追加(a)的模式打开。如果设置了pwd参数,则其将会覆盖setpassword(pwd)方法设置的默认密码。对一个已经关闭的ZipFile调用read()方法将会引发RuntimeError
read(name, pwd=Noneds)

# 将filename文件写入归档文件,可以通过arcname指定新文件名(需要注意的是文件名中磁盘盘符和开头的路径分隔符都会被移除);compress_type表示压缩方法,如果指定了该参数则会覆盖ZipFile构造方法中的compression参数指定的值;要调用此方法,归档文件必须以'w', 'a'或'x'模式打开,如果对以'r'模式打开的ZipFile调用write()方法或者对已关闭的ZipFile调用write()方法将会引发RuntimeError
write(filename, arcname=None, compress_type=None)

# 将一个字节串写入归档文件;zinfo_or_arcname可以是归档文件中的文件名称,也可以是一个ZipInfo实例
writestr(zinfo_or_arcname, bytes[, compress_type])

更多详情见请继续阅读下一页的精彩内容http://www.linuxidc.com/Linux/2017-05/144323p2.htm

linux
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数

       

评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款