前言时刻:

又到了总结的时候,今天学的不多

总结一波:

今天学习了shutil模块,logging模块

1、shutil模块

Python 官方把shutil 模块定义为高级文件操作模块,主要涉及文件夹和文件的复制、删除以及压缩文件等用法

1)shutil.rmtree(path, ignore_errors=False, onerror=None):删除文件夹

  • path:必须是一个文件夹路径
  • ignore_errors:为 True 时,若发生错误则忽略错误不报错,反之。
  • onerror:发生错误式,回调一个函数如:func(function, path和 excinfo。)

os中的os.path.move是只可以删除空文件夹或者文件,不可以删除带有非空文件夹。使用 shutil.rmtree 就可搞定。

  1. import shutil
  2. # 1、shutil.rmtree
  3. shutil.rmtree("test", ignore_errors=True)

2)shutil.move(src, dst, copy_function=shutil.copy2):移动文件夹

通过递归方法,将文件夹 src 中的内容移动到文件夹 dst 里面,并返回 dst 的路径。

注意:如果 dst 目录已经存在,则src文件夹会放到 dst 目录文件夹里面。

  1. # shutil.move
  2. # 环境:test02文件夹已存在
  3. shutil.move('test03', 'test02', copy_function=shutil.copy2)
  4. # 'test02/test03'

3)shutil.copy2(src, dst, *, follow_symlinks=True):复制文件,但会尝试保留文件元数据。

  • src:原文件的路径
  • dst:目标路径,文件夹或文件名都可。
  • follow_symlinks:
  1. # shutil.move
  2. shutil.copy2('test2.txt', 'test3_copy2.txt') # test3_copy2.txt
  3. shutil.copy('test2.txt', 'test3_copy.txt') # test3_copy.txt

相对应的是shutil.copy(src, dst, *, follow_symlinks=True)只会复制文件的数据和权限,其他的都不会复制。

shutil.copy和copy2对比.png

4)shutil.copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, ignore_dangling_symlinks=False, dirs_exist_ok=False):复制文件夹

  • src:原文件夹路径
  • dst:文件夹目录不能存在,否则为空,他默认自己创建目录。
  • ignore:设置不复制一些文件,

将 src 的整个目录复制到 dst 目录下,设置ignore则忽略一些文件,shutil.ignore_patterns()支持正则表达式。

  1. # 4、shutil.copytree
  2. shutil.copytree('test02', './test06', ignore=shutil.ignore_patterns("*.py", 'test[0-9].txt'))
  3. # './test06'

1.5 shutil.disk_usage

shutil.disk_usage(path):获取路径所在的磁盘使用情况,返回一个元组:total used free

  1. total, used, free = shutil.disk_usage('./')
  2. print(f"磁盘大小:{round(total/(1024*1024*1024), 1)} GB, 已使用:{round(used/(1024*1024*1024), 1)} GB, 剩余:{round(free/(1024*1024*1024), 1)} GB")
  3. # 磁盘大小:465.6 GB, 已使用:230.3 GB, 剩余:219.0 GB

1.6 shutil.make_archive

shutil.make_archive(*base_name*, *format*[, *root_dir*[, *base_dir*[, *verbose*[, *dry_run*[, *owner*[, *group*[, *logger*]]]]]]]) 压缩文件/文件夹。

shutil.unpack_archive(*filename*[, *extract_dir*[, *format*]]):解压文件

2、logging日志模块

python的日志模块,超级重要,尤其是在项目中。日志的作用如:

  1. 记录用户的行为 — 做数据分析
  2. 排查代码中的错误。

日志的级别有(优先级从低到高):debug(调试)->info(通知)->warning->error(错误)->crtical(批评的)

日志等级(level) 描述
DEBUG 最详细的日志信息,典型应用场景是 问题诊断
INFO 信息详细程度仅次于DEBUG,通常只记录关键节点信息,用于确认一切都是按照我们预期的那样进行工作
WARNING 当某些不期望的事情发生时记录的信息(如,磁盘可用空间较低),但是此时应用程序还是正常运行的
ERROR 由于一个更严重的问题导致某些功能不能正常运行时记录的信息
CRITICAL 当发生严重错误,导致应用程序不能继续运行时记录的信息
  1. logging.debug("调试")
  2. logging.info("通知 hi~")
  3. logging.warning("警告")
  4. logging.error("错误")
  5. logging.critical("批评 严厉")
  6. # WARNING:root:警告
  7. # ERROR:root:错误
  8. # CRITICAL:root:批评 严厉
  9. # 我们可以看出默认是打印warning以上的日志,如果想显示debug和info的,需要设置一下日志级别。

2.1 设置日志级别

  1. logging.basicConfig(**kwargs)
格式 描述
filename 使用指定的文件名而不是 StreamHandler 创建 FileHandler。
filemode 如果指定了 filename,则用此 模式
打开该文件。 默认模式为 'a'
format 使用指定的格式字符串作为处理程序。 默认为属性以冒号分隔的 levelname
, name
message
datefmt 使用指定的日期/时间格式,与 [time.strftime()](https://docs.python.org/zh-cn/3.8/library/time.html#time.strftime)
所接受的格式相同。
style 如果指定了 format,将为格式字符串使用此风格。 '%'
, '{'
'$'
分别对应于 printf 风格
, [str.format()](https://docs.python.org/zh-cn/3.8/library/stdtypes.html#str.format)
[string.Template](https://docs.python.org/zh-cn/3.8/library/string.html#string.Template)
。 默认为 '%'
level 设置根记录器级别去指定 level
.
stream 使用指定的流初始化 StreamHandler。 请注意此参数与 filename 是不兼容的 - 如果两者同时存在,则会引发 ValueError
handlers 如果指定,这应为一个包含要加入根日志记录器的已创建处理程序的可迭代对象。 任何尚未设置格式描述符的处理程序将被设置为在此函数中创建的默认格式描述符。 请注意此参数与 filenamestream 不兼容 —— 如果两者同时存在,则会引发 ValueError
force 如果将此关键字参数指定为 true,则在执行其他参数指定的配置之前,将移除并关闭附加到根记录器的所有现有处理器。

1)简单设置日志级别:

  1. logging.basicConfig(level=logging.DEBUG)
  2. logging.debug("就调试一下")
  3. # 就调试一下

2)设置日志的输出格式:

一般的项目中日志主要是有:时间+日志级别+py名称+所在行+消息

  1. logging.basicConfig(level=logging.INFO,
  2. format="%(asctime)s - %(name)s - %(levelname)s - %(module)s - %(lineno)d - %(message)s",
  3. )
  4. logging.info("这是一个通知")
  5. # 2021-06-13 18:45:52,403 - root - INFO - day21-shutil和logging模块 - 6 - 这是一个通知

更多的 format 中的参数可见下方:

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

3)将日志存储到文件中并切割日志:

  1. # file_handler 是设置操作写入文件的句柄,将日志写入到文件中。
  2. file_handler = logging.FileHandler(filename='test.log', mode='at', encoding='utf8')
  3. logging.basicConfig(handlers=[file_handler],
  4. format="%(asctime)s - %(name)s - %(levelname)s - %(lineno)s - %(message)s",
  5. level=logging.DEBUG,
  6. )
  7. logging.warning("name")
  8. # test.log 2021-06-13 21:29:30,108 - root - WARNING - <ipython-input-5-851c13859979> - name

设置切割日志,有两种方式:

  1. 一种是按时间切割,每多少秒切割出一个日志。可设置保留日志的个数,超出个数自动清理就内容。
  2. 另一种是按大小切割,超过一定大小后就切割出一个日志,同样可设置保留日志的个数,超出个数自动清理就内容。
  1. # 日志切割操作
  2. size_split = logging.handlers.RotatingFileHandler("test01.log", maxBytes=1024*1024, backupCount=5) # 满1MB 就切割,备份数量5份
  3. time_split = logging.handlers.TimedRotatingFileHandler("test02.log", when='s', interval=10, backupCount=5)
  4. # when interval间隔的单位,表示每 interval 时间就备份,可取:s、h、d等
  5. logging.basicConfig(
  6. format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
  7. datefmt='%Y-%m-%d %H:%M:%S %p',
  8. handlers=[size_split,time_split],
  9. level=logging.ERROR
  10. )
  11. for i in range(1,100000):
  12. time.sleep(1)
  13. logging.error('KeyboardInterrupt error %s'%str(i))

4)设置日志即可存储到文件又可打印到屏幕上:

添加一个logging.StreamHandler()输出到屏幕的 handler ,以及一个写入到文件的 handler 即可。

  1. # 日志切割操作
  2. import time
  3. import logging
  4. sh = logging.StreamHandler()
  5. file_handler = logging.FileHandler(filename='test03.log', mode='a', encoding='utf8')
  6. logging.basicConfig(
  7. format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
  8. datefmt='%Y-%m-%d %H:%M:%S %p',
  9. handlers=[sh, file_handler],
  10. level=logging.ERROR
  11. )
  12. for i in range(1,10):
  13. # time.sleep(1)
  14. logging.error('KeyboardInterrupt error %s'%str(i))

总结:

重点掌握并融会贯通。

参考文章:

https://docs.python.org/zh-cn/3/library/shutil.html#shutil.make_archive

https://docs.python.org/zh-cn/3/library/logging.html

https://www.cnblogs.com/Eva-J/articles/7228075.html#_label14