• python 全栈开发,Day26(hashlib文件一致性,configparser,logging,collections模块)


      

    一,hashlib 文件一致性校验

    为何要进行文件一致性校验?

    为了确保你得到的文件是正确的版本,而没有被注入病毒和木马程序。例如我们经常在网上下载软件,而这些软件已经被注入了一些广告和病毒等,如果不进行文件与原始发布商的一致性校验的话,可能会给我们带来一定的损失。

    文件一致性校验原理
    要进行文件的一致性校验,我们不可能像文本文件比较那样,将两个文件放到一起对比,因为很多的时候文件很大。目前最理想的办法就是,是通过加密算法,对文件生成对应的值,通过生成的值与发布商提供的值比较来确认两个文件是否一致。

    MD5和SHA1就是目前使用最为广泛的良种加密算法。

    举例:

    先手动创建2个文件,file1 和 file 2 ,内容123

    使用MD5计算file1的加密值

    import hashlib
    md5obj = hashlib.md5()
    with open('file1','rb')as f:
        content = f.read()
        md5obj.update(content)
    print(md5obj.hexdigest())
    

    执行后输出:

    再计算fiel2的加密值,再把上面的代码复制一遍?太low了,如果有多个文件怎么办?  

    定义一个方法:

    import hashlib
    def check_md5(filename):
        md5obj = hashlib.md5()
        with open(filename,'rb')as f:
            content = f.read()
            md5obj.update(content)
        return md5obj.hexdigest()
    ret1 = check_md5('file1')
    ret2 = check_md5('file2')
    print(ret1)
    print(ret2)
    

     执行输出:

    这样就可以知道,两个文件是否一致了。

    但是上面的方法,有一个缺陷,当文件达到GB级别的时候那内存怎么支撑?(这种比对相当于要先把所有的文件都读入内存中)

    那么怎么办?先看下面的一个小栗子:

    import hashlib
    md5obj = hashlib.md5()
    md5obj.update(b'john')  #b 'string'表示bytes类型,不能有中文符号
    print(md5obj.hexdigest())

    拆分字符串

    import hashlib
    md5obj = hashlib.md5()   #创建MD5对象
    md5obj.update(b'john')   #拆分字符串
    md5obj.update(b'alen')
    print(md5obj.hexdigest())
    

    执行输出:

    结论:

    一段字符串直接进行摘要和分成几段摘要的结果是相同的

    那么就可以把大文件,分段进行MD5加密,就可以了

    那么就可以把大文件,分段进行md5加密,就可以了

    下载一部电影《海上钢琴师》,文件有1.58GB

    本片讲述了一个钢琴天才传奇的一生。 豆瓣评分9.2

    计算电影的md5值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import hashlib
    def check(filename):
        md5obj = hashlib.md5()
        with open(filename,'rb') as f:
            while True:
                content = f.read(1048576)  # 每次读取1048576字节,也就是1MB
                if content:
                    md5obj.update(content)
                else:
                    break  # 当内容为空时,终止循环
        return md5obj.hexdigest()
     
    ret1 = check('E:迅雷下载[迅雷下载www.2tu.cc]海上钢琴师.BD1280高清中英双字.rmvb')
    print(ret1)

    花费了9秒,执行输出:

    30c7f078203d761d3f13bec6f8fd3088

    总结:

    序列化 把数据类型变成字符串

      为什么要有序列化,因为在网络上和文件中能存在的只有字节

    json

      在所有的语言中通用,只对有限的数据类型进行序列化 字典 列表 字符串 数字 元祖

      在多次写入dump数据进入文件的时候,不能通过load来取。

    pickle

      只能在python种使用,对绝对大多数数据类型都可以进行序列化

      在load的是哦湖,必须拥有load数据类型对应的类在内存里

      dumps 序列化

      loads 反序列化

      dump 直接向文件中序列化

      load 直接对文件反序列化

    shelve

      f = open() 打开文件

    json 和 pickle 必须熟练掌握

    二,configarser模块

      该模块适用于配置文件的格式与windows ini 文件类似,可以包含一个或多个字节(section),每个字节可以有多个参数(键=值).

    创建文件

    来看一个好多软件的常见文档格式如下:

    section 称之为节点,节点里面赋值对,称之为项

    如果想用python生成一个这样的文档怎么做呢?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import configparser
     
    config = configparser.ConfigParser()  #创建一个ConfigParser对象
     
    config["DEFAULT"= {'ServerAliveInterval''45',  #默认参数
                          'Compression''yes',
                         'CompressionLevel''9',
                         'ForwardX11':'yes'
                         }
    config['bitbucket.org'= {'User':'hg'#添加一个节点bitbucket.org
    config['topsecret.server.com'= {'Host Port':'50022','ForwardX11':'no'}
     
    with open('example.ini''w') as configfile: #写入配置文件example.ini
       config.write(configfile)

    执行程序,查看example.ini的内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [DEFAULT]
    serveraliveinterval = 45
    forwardx11 = yes
    compression = yes
    compressionlevel = 9
     
    [bitbucket.org]
    user = hg
     
    [topsecret.server.com]
    forwardx11 = no
    host port = 50022

    可以看出节点的项,都变成小写了。

    这是因为它在写入的时候,将所有字符串使用了lower()方法,转换为小写了。

    查找文件

    import configparser
    config = configparser.ConfigParser()
    config.read('example.ini')          ###上面内容为固定部分###
    print(config.sections())            # 查看所有的节点,但默认不显示DEFAULT,返回列表  

    执行输出:

    下面的代码,固定部分我就不贴了

    1
    print('bitbucket.org' in config)  # 验证某个节点是否在文件中

    执行输出: True

    1
    print(config['bitbucket.org']['user'])  # 查看某节点下面的某个项的值

    执行输出: hg

    1
    print(config['bitbucket.org'])  # 输出一个可迭代对象

    执行输出: <Section: bitbucket.org>

    1
    2
    3
    #使用for循环一个可迭代对象
    for key in config['bitbucket.org']:  # 注意,有default时,会默认输出它的键
        print(key)

    执行输出:

    user
    serveraliveinterval
    forwardx11
    compression
    compressionlevel

    1
    print(config.items('bitbucket.org'))  # 找到'bitbucket.org'下所有的键值对

    执行输出:

    [('serveraliveinterval', '45'), ('forwardx11', 'yes'), ('compression', 'yes'), ('compressionlevel', '9'), ('user', 'hg')]

    1
    print(config.get('bitbucket.org','compression'))  # get方法section下的key对应的value

    执行输出: yes

    增删改操作

    增加一个节点

    1
    print(config.add_section('yuan'))  # 增加一个节点

    注意,它不会立即写入!必须执行下面的代码

    1
    config.write(open('example.ini'"w")) # 写入文件

    open('example.ini',w) 表示清空文件

    config.write 表示写入内容

    再次查看文件内容:

    [DEFAULT]
    serveraliveinterval = 45
    forwardx11 = yes
    compression = yes
    compressionlevel = 9
    
    [bitbucket.org]
    user = hg
    
    [topsecret.server.com]
    forwardx11 = no
    host port = 50022
    
    [yuan]
    

     删除一个节点

    config.remove_section('bitbucket.org')
    config.write(open('example.ini','w'))
    

     修改节点

    1
    2
    config.set('yuan','k2','222')  # yuan节点增加项k2 = 222
    config.write(open('example.ini'"w")) # 写入文件

    总结:

    section 可以直接操作它的对象来获取所有的节信息

    option 可以通过找到的节来查看多有项

    三,loggin

    为了保护数据安全
    所有的增加,修改,删除操作,都要记录日志

    比如log日志,管理员操作日志,消费记录...

    日志给我们在内部操作的时候提供很多遍历
    日志给用户提供更多的信息
    在程序使用的过程中自己调试需要看的信息
    帮助程序员排查程序的问题

    ogging模块 不会自动帮你添加日志的内容
    你自己想打印什么 你就写什么

    import logging
    logging.debug('debug message')
    logging.info('info message')
    logging.warning('warning message')
    logging.error('error message')
    logging.critical('critical message')
    

    执行输出: 

    设置INFO,只显示INFO以上的错误

    能不能只显示一种级别信息呢?不行!
    只能打印某个级别以上的信息

    增加时间显示

    import logging
    logging.basicConfig(level=logging.DEBUG,
                        format='%(asctime)s %(filename)s[line:%(lineno)d] '
                               '%(levelname)s %(message)s')
    logging.debug('debug message')  #debug调试模式 级别模式
    logging.info('info message')    #info 显示正常信息
    logging.warning('warning messafe')  #warning 显示警告信息
    logging.error('error message')      #error 显示错误信息
    logging.critical('critical message') #critical 显示验证错误信息
    

     执行输出:

    设置时间格式

    #设置时间格式
    import logging
    logging.basicConfig(level=logging.DEBUG,
                        format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s'),
    datefmt = '%a, %d %b %y %H:%M:%S',
    logging.debug('debug message')       # debug 调试模式 级别最低
    logging.info('info message')         # info  显示正常信息
    logging.warning('warning message')   # warning 显示警告信息
    logging.error('error message')       # error 显示错误信息
    logging.critical('critical message') # critical 显示验证错误信息
    

      执行输出:

    logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有:
    
    filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。
    filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
    format:指定handler使用的日志显示格式。
    datefmt:指定日期时间格式。
    level:设置rootlogger(后边会讲解具体概念)的日志级别
    stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。
    
    format参数中可能用到的格式化串:
    %(name)s Logger的名字
    %(levelno)s 数字形式的日志级别
    %(levelname)s 文本形式的日志级别
    %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
    %(filename)s 调用日志输出函数的模块的文件名
    %(module)s 调用日志输出函数的模块名
    %(funcName)s 调用日志输出函数的函数名
    %(lineno)d 调用日志输出函数的语句所在的代码行
    %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
    %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
    %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
    %(thread)d 线程ID。可能没有
    %(threadName)s 线程名。可能没有
    %(process)d 进程ID。可能没有
    %(message)s用户输出的消息
    

    写入文件

      

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import logging
    logging.basicConfig(level=logging.DEBUG,
                        format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                        datefmt='%a, %d %b %y %H:%M:%S',
                        filename = 'userinfo.log'
                        )
    logging.debug('debug message')       # debug 调试模式 级别最低
    logging.info('info message')         # info  显示正常信息
    logging.warning('warning message')   # warning 显示警告信息
    logging.error('error message')       # error 显示错误信息
    logging.critical('critical message'# critical 显示验证错误信息

    执行程序,查看文件内容

    某些情况下,查看文件是乱码的。

    它的局限性有2个

      编码格式不能设置

      不能同时输出到文件和屏幕

    loggin 对象方式

     由于简单配置有局限性,logging对象方式更为灵活

    import logging
    logger = logging.getLogger()   #实例化了一个logger对象
    #国外叫handler,中国翻译过来,叫句柄
    #设置文件名和编码 fh = logging.FileHandler('test.log',encoding='utf-8') #实例化了一个文件句柄 sh = logging.StreamHandler() #用于输出到控制台 fmt = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') fh.setFormatter(fmt) sh.setFormatter(fmt) #吸星大法 logger.addHandler(fh) logger.addHandler(sh) logger.setLevel(logger.DEBUG) logger.debug('debug message') logger.info('info message') logger.warning('warning message')

    执行输出:

    warning message

    查看文件内容,也是

    warning message

    这样就具备了同时写入文件以及输出屏幕的技能

    增加输出格式功能:

      

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    import logging
    logger = logging.getLogger()  # 实例化了一个logger对象
    #在国外叫handler,在中国翻译过来,叫句柄
    #设置文件名和编码
    fh = logging.FileHandler('test.log',encoding='utf-8')  # 实例化了一个文件句柄 # 格式和文件句柄或者屏幕句柄关联
    sh = logging.StreamHandler()  # 用于输出到控制台
     
    fmt = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')  # 格式化
    fh.setFormatter(fmt)  # 格式和文件句柄或者屏幕句柄关联
    sh.setFormatter(fmt)
     
    #吸星大法
    logger.addHandler(fh)  # 吸收写文件功能 和logger关联的只有句柄
    logger.addHandler(sh)  # 吸收输出屏幕功能
    logger.setLevel(logging.DEBUG)  # 设置警告级别为debug,此处DEBUG源码为DEBUG = 10
     
    logger.debug('debug message')
    logger.info('info message')
    logger.warning('warning message')

    执行输出:

    2018-04-23 20:16:58,850 - root - DEBUG - debug message
    2018-04-23 20:16:58,850 - root - INFO - info message
    2018-04-23 20:16:58,850 - root - WARNING - warning message

    查看文件内容,也是一样的。

     

  • 相关阅读:
    安卓清理缓存怎么做(未完)
    【转】来讨论下 Android 面试该问什么?
    解决app安装成功后,直接点击“打开”再按home返回,再次打开app会重新启动的问题
    Android切换横竖屏不销毁前台Activity,也不影响后台Activity
    Android布局:宽度适应的横向跟随,防止挤掉重要视图
    Android上的Badge,快速实现给应用添加角标
    博客上传图片存储解决
    ViewComponent组件在框架中使用
    Git日常使用命令
    js中的preventDefault与stopPropagation详解
  • 原文地址:https://www.cnblogs.com/haowen980/p/8922116.html
Copyright © 2020-2023  润新知