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个

  编码格式不能设置

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

 

 

猜你喜欢

转载自www.cnblogs.com/haowen980/p/8922116.html