python文件与文件路径管理
python标准库的os模块包含与操作系统的系统环境、文件系统、用户数据库以及权限进行交互的函数。
Linux下的路径分隔符是"/",Windows下的路径分割符是"\"。
os.path进行路径和文件管理
getcwd 获取当前目录
import os
os.getcwd()
#输出如下
#转到当前目录D:\project\bianzu下
os.listdir('.')
#['email_bianzu.py', 'email_bianzu_win.py', 'email_test1.py']
split 返回一个二元组,包含文件的路径与文件名
import os
path = r"D:\project\bianzu\email_bianzu.py"
print(os.path.split(path))
#输出如下所示:
('D:\\project\\bianzu', 'email_bianzu.py')
dirname 返回文件的路径
path = r"D:\project\bianzu\email_bianzu.py"
print(os.path.dirname(path))
#输出如下所示:
D:\project\bianzu
返回文件的文件名
path = r"D:\project\bianzu\email_bianzu.py"
print(os.path.basename(path))
#输出如下所示:
email_bianzu.py
得到文件或路径的绝对路径
path = r"D:\project\bianzu\email_bianzu.py"
print(os.path.abspath('.'))
#输出如下所示:
D:\project\bianzu
join 根据不同的操作系统平台,使用不同的路径分割符拼接路径
print(os.path.join("D:\project","test","bianzu.py"))
# 输出结果如下所示
D:\project\test\bianzu.py
判断文件类型
os.path模块也提供了若干函数用来判断路径是否存在,以及路径所指文件的类型
1 exists 参数path所指向的路径是否存在
2 isfile 参数path所指向的路径存在,并且是一个文件
3 isdir 参数path所指向的路径存在,并且是一个文件夹
使用os模块管理文件和目录
os模块包含的文件和目录操作函数,包括创建目录、删除目录、删除文件、重命名文件等
1 unlink/remove: 删除path路径所指向的文件
2 rmdir: 删除path路径指向的文件夹,该文件夹必须为空,否则会报错
3 mkdir:创建一个文件夹
4 rename: 重命名文件或文件夹
os.remove("1.jpg")
os.rmdir("dir1")
os.mkdir(r"/home/bianzu/tmp/")
os.rename("mydir","newdir")
os模块包含了修改文件权限、判断文件权限的函数
os提供了三个常量来表示读、写、可执行权限,即R_OK、W_OK和X_OK
1 chmod用来修改文件的权限
1 access用来判断文件是否具有相应的权限
示例:通过命令行读取文件名称,先判断文件是否存在,如果文件不存在,则直接退出。然后判断文件是否具有读权限,如果没有读权限,将文件赋予所有用户都具有读写执行权限。如果文件存在并且已经具有读权限,读取文件内容
import sys
import os
def main():
filename = sys.argv[1]
print(filename)
if not os.path.isfile(filename):
raise SystemExit(filename + ' does not exists')
elif not os.access(filename,os.R_OK):
os.chmod(filename, 777)
else:
with open(filename) as f:
print(f.read())
if __name__ == "__main__":
main()
高级文件处理接口shutil
os模块是对操作系统的接口进行封装,主要作用是跨平台。shutil模块包含复制、移动、重命名和删除文件及目录的函数,主要作用是管理文件和目录。
复制文件和文件夹
copy用来拷贝一个文件,copytree用来拷贝一个目录
import shutil
shutil.copy('a.py','b.py')
shutil.copytree('dir1','dir2')
文件和文件夹的移动与改名
shutil模块中的move(src,dst)用来将路径src处的文件移动到dst处,并返回新位置的绝对路径。dst是一个目录,则将文件移动到目录之中。dst是一个文件名称,则将文件移动到目标目录下,并重命名为dst
import shutil
shutil.move("a.py","b.py")
shutil.move("a.py","dir1")
删除目录
删除文件,可以使用os模块的remove和unlink函数,删除目录,可以使用os模块的rmdir和removedirs函数。但rmdir和removedirs都要求被删除的目录非空不能进行强制删除,shutil.rmtree不管目录是否非空,都直接删除整个目录。
# 删除目录
shutil.rmtree("/home/bianzu/tmp/")
# 再建立目录
os.mkdir(r"/home/bianzu/tmp/")
文件内容管理
filecmp模块包含了比较目录和文件的操作。
cmp函数
cmp函数用来比较两个文件是否相同,如果文件相同,返回True,否则返回False
import filecmp
filecmp.cmp('a.txt','b.txt')
False
cmpfiles
cmpfiles函数用来同时比较两个不同目录下的多个文件,并且返回一个三元组,分别包含相同的文件、不同的文件和无法比较的文件
import filecmp
filecmp.cmpfiles('dir1','dir2',['a.txt','b.txt','a_copy.txt'])
#输出如下所示:
(['a.txt'],['b.txt'],['a_copy.txt'])
dircmp函数
dircmp函数用来比较两个目录,会返回一个dircmp类的对象,该对象保存了诸多属性
import filecmp
d=filecmp.dircmp(r"D:\tmp\test",r"D:\tmp\test1")
d.report()
# 输出如下所示
diff D:\tmp\test D:\tmp\test1
Only in D:\tmp\test : ['test2.txt']
Only in D:\tmp\test1 : ['a.txt', 'data.txt']
Identical files : ['test3.txt', 'test4.txt']
filecmp模块的dircmp函数仅仅比较目录下面的文件和子目录,不会递归比较目录内容。
MD5校验和比较
通过校验码的方式对文件进行比较。校验码是通过散列函数计算而成,是一种从任何数据中创建小的数字指纹方法。散列函数把消息或数据压缩成摘要,使得数据量变小,便于进行比较。MD5是目前使用最广泛的散列算法。
MD5哈希一般用于检查文件完整性,尤其常用于检测文件传输、磁盘错误或其他情况下文件的正确性。
在linux下计算文件的MD5校验码,只需要以文件名为参数调用md5sum命令即可。
md5sum test.txt
fad5096b8f92d0e906a87dce2e371471 test.txt
在python中计算文件的MD5校验码使用标准库中的hashlib模块即可。
import hashlib
d =hashlib.md5()
with open('D:/tmp/a.txt') as f:
for line in f:
d.update(line.encode('utf-8'))
print(line)
print(d.hexdigest())
# 输出如下所示
hi,happy everyday
3add452390c4bfaf7692a4fece6e108c
完整案例:找到目录下的重复文件
首先通过find_specific_files函数找到目录下的所有文件,通过MD5校验码判断文件是否相同。将计算文件的MD5校验码的功能封装成一个名为get_file_checksum函数,该函数接受文件名作为参数,返回文件的MD5校验功能。
#-*- coding: UTF-8 -*-
import os
import fnmatch
import hashlib
import sys
CHUNK_SIZE = 8192
def is_file_match(filename,patterns):
for pattern in patterns:
if fnmatch.filter(filename,pattern):
return True
return False
# 查找目录下所有文件,指定pattern的话,则是查找符合patterns的文件
def find_specific_files(root,patterns=['*'],exclude_dirs = []):
for root,dirnames,filenames in os.walk(root):
for exclude_dir in exclude_dirs:
if exclude_dir in dirnames:
dirnames.remove(exclude_dir)
for filename in filenames:
if is_file_match(filename,patterns):
yield os.path.join(root,filename)
def get_chunk(filename):
#UnicodeDecodeError: 'gbk' codec can't decode byte 0xff in position 0: illegal multibyte sequence
#遇到有些编码不规范的文件,遇到UnicodeDecodeError,因为在文本文件中可能夹杂了一些非法编码的字符。遇到这种情况,open()函数还接收一个errors参数,
# 表示如果遇到编码错误后如何处理。最简单的方式是直接忽略:
with open(filename,errors='ignore') as f:
while True:
chunk = f.read(CHUNK_SIZE)
if not chunk:
break
else:
yield chunk
def get_file_checksum(filename):
h = hashlib.md5()
for chunk in get_chunk(filename):
#出现这个报错TypeError: Unicode-objects must be encoded before hashing
#是因为python3中字符对象是unicode对象,不能直接加密
h.update(chunk.encode("utf-8"))
return h.hexdigest()
def main():
sys.argv.append("")
directory = sys.argv[1]
if not os.path.isdir(directory):
raise SystemExit(f"{directory} is not a directory")
record = {}
for item in find_specific_files(directory):
checksum = get_file_checksum(item)
if checksum in record:
print(f"find duplicate file: {record[checksum]} vs {item}")
else:
record[checksum] = item
if __name__ == '__main__':
main()