前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python之文件内容管理

Python之文件内容管理

作者头像
SEian.G
发布2021-04-15 14:42:36
5020
发布2021-04-15 14:42:36
举报
文章被收录于专栏:SEian.G学习记录

作为DBA,在日常运维管理中,经常会有一些文件内容等相关的处理需求,那么就可能会有这样的疑问:

1)两个目录中的文件到底有什差别? 2)系统中有多少重复文件存在? 3 )如何找到并删除系统中的重复文件?

在这一篇文章中,将重点介绍如何使用Python解决这几个问题

一、目录和文件比较

filecmp模块包含了比较目录和文件的操作为了对filecmp模块进行测试和验证,我们在当前下创建如下文件和目录:

代码语言:javascript
复制
[root@VM-17-4-centos filecmp_tmp]# tree
.
├── dir1
│   ├── a_copy.txt
│   ├── a.txt
│   ├── b.txt
│   ├── c.txt
│   └── subdir1
│       └── d.txt
└── dir2
    ├── a.txt
    ├── b.txt
    ├── c.txt
    └── subdir1
        └── e.txt
 
In [1]: import filecmp
 
In [5]: filecmp.cmp('a.txt','b.txt')
Out[5]: False
 
In [6]: filecmp.cmp('a.txt','a_copy.txt')
Out[6]: True

filecmp下还有个名为cmpfiles的函数,该函数用来同时比较两个不同目录下的多个文件,并且返回一个三元组,分别包含相同的文件、不同的文件和无法比较的文件在测试环境的顶层目录执行以下代码后效果如下:

代码语言:javascript
复制
In [9]: filecmp.cmpfiles('dir1','dir2',['a.txt','b.txt','c.txt','a_copy.txt'])
Out[9]: (['c.txt'], ['a.txt', 'b.txt'], ['a_copy.txt'])

cmpfiles函数用来同时比较两个目录下的文件,也可以使用该函数比较两个目录,但是,在比较两个目录时需要通过参数指定所有可能的文件,显然比较繁琐,filecmp中还提供了一个名为dircmp的函数用来比较两个目录。

调用diremp函数以后会返回一个dircmp类的对象,该对象保存了诸多属性,工程师可以通过读取这些属性的方式获取目录之间的差异如下所示:

代码语言:javascript
复制
In [10]: d=filecmp.dircmp('dir1','dir2')
 
In [11]: d.report()
diff dir1 dir2
Only in dir1 : ['a_copy.txt']
Identical files : ['c.txt']
Differing files : ['a.txt', 'b.txt']
Common subdirectories : ['subdir1']
 
In [13]: d.left_list
Out[13]: ['a.txt', 'a_copy.txt', 'b.txt', 'c.txt', 'subdir1']
 
 
In [14]: d.left_only
Out[14]: ['a_copy.txt']
 
 
In [15]: d.right_list
Out[15]: ['a.txt', 'b.txt', 'c.txt', 'subdir1']
 
In [16]: d.right_only
Out[16]: []

从这里的测试可以看到,filecmp模块的dircmp函数仅仅比较目录下面的文件和子目录,但是,并不会递归比较子目录的内容,对于目录,dircmp函数也仅仅是比较函数的名称,不会去比较子目录里面的内容。例如,这个例子中的dir1/subdir1,dir2/subdir里面的文件完全不同,但是dircmp并不会报它们之间的差异

二、MD5文件校验和比较

前面介绍如何使用filecmp模块对文件和目录进行比较,虽然filecmp比较文件和目录的使用方式比较简单,但它有很多无法处理的情况,例如,找到当前目录和子目录下所有相同的文件,比较不同计算机上的文件是否相同。简单的比较两个文件是否相或者比较两个目录下的文件差异,很多时候并不能满足我们的需求;这个时候,可以通过校验码(checksum)的方式对文件进行比较

校验码是通过散列函数计算而成,是一种从任何数据中创建小的数字“指纹”的方法,散列函数把数据缩成摘要,使得数据量变小,便于进行比较;MD5是目前使用广泛的散列算法,理论上看MD5哈希值可对应无限个文件,但从现实的角度来看,两个不同文件几乎不可能有相同的MD5哈希值,任何对一个文件的非恶意变更都会导致MD哈希值改变,因此,MD5哈希一般用于检查文件完整性,尤其常用于检测文件传磁盘错误或他情况下文件的正确性

代码语言:javascript
复制
In [17]: import hashlib
 
In [18]: d=hashlib.md5()
 
In [20]: with open('/etc/group') as f:
    ...:     for line in f:
    ...:         d.update(line)
    ...:         
 
In [21]: d.hexdigest()
Out[21]: '1b76f600aa8008757c921870a8ebe281'

案例:找到目录下的重复文件

接下来看一个综合案例,在这个例子中,我们要找到某个目录下所有的重复文件,先通过find_specific_files函数找到目录下的所有文件,然后通MD5校验判断文件否相同,为了让代码尽可能的通用,我们将计算文件的MD5校验码的功能封装个名为get_file_ checksum的函数,该函数接受文件名作为参数返回文件D5验码功能的现如下所示:

代码语言:javascript
复制
# -*- coding: utf-8 -*-
import os
import fnmatch
import sys
import hashlib
 
CHUNK_SIZE = 8192
 
def is_file_match(filename, patterns):
    for pattern in patterns:
        if fnmatch.fnmatch(filename, pattern):
            return True
    return False
 
def find_specific_files(root, patterns=['*'], exclude_dirs=[]):
    for root, dirnames, filenames in os.walk(root):
        for filename in filenames:
            if is_file_match(filename, patterns):
                yield os.path.join(root, filename)
        for d in exclude_dirs:
            if d in dirnames:
                dirnames.remove(d)
 
def get_chunk(filename):
    with open(filename) 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):
        h.update(chunk)
    return h.hexdigest()
 
def main():
    sys.argv.append("")
    directory = sys.argv[1]
 
 
    if not os.path.isdir(directory):
        raise SystemExit("{0} is not a directory ".format(directory))
 
 
    record = {}
    for item in find_specific_files(directory):
        checksum = get_file_checksum(item)
        if checksum in record:
            print 'find duplicate file: {0} vs {1}'.format(record[checksum], item)
        else:
            record[checksum] = item
 
if __name__ == '__main__':
    main()
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DBA的辛酸事儿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、目录和文件比较
  • 二、MD5文件校验和比较
  • 案例:找到目录下的重复文件
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档