【Python】从入门到上头—常用内置模块基础应用(13)

news2024/11/23 16:59:52

文章目录

  • datetime
  • base64
  • hashlib
  • hmac
  • urllib
  • XML
  • HTMLParser
  • random
  • 小结

datetime

datetime是Python处理日期和时间的标准库。

获取当前日期时间

from datetime import datetime
now = datetime.now()  # 获取当前datetime
print(now) #2023-09-13 10:28:48.621343
print(type(now))#<class 'datetime.datetime'>
  • 注意到datetime是模块,通过from datetime import datetime导入的才是datetime这个类。
    • 如果仅导入import datetime,则必须引用全名datetime.datetime

获取指定日期和时间

dt = datetime(2023, 9, 13, 12, 20) # 用指定日期时间创建datetime
print(dt)

datetime转换为timestamp

  • 在计算机中,时间实际上是用数字表示的。我们把1970年1月1日 00:00:00 UTC+00:00时区的时刻称为epoch time,记为0(1970年以前的时间timestamp为负数),当前时间就是相对于epoch time的秒数,称为timestamp。
dt = datetime(2023, 9, 13, 12, 20)  # 用指定日期时间创建datetime
print(dt.timestamp()) # 把datetime转换为timestamp
#1694578800.0
  • 注意Python的timestamp是一个浮点数,整数位表示秒

timestamp也可以直接被转换到UTC标准时区的时间:

t = 1429417200.0
print(datetime.fromtimestamp(t)) # 本地时间
#2015-04-19 12:20:00
print(datetime.utcfromtimestamp(t)) # UTC时间
#2015-04-19 04:20:00

str转换为datetime

  • 通过datetime.strptime()实现,需要一个日期和时间的格式化字符串:
cday = datetime.strptime('2015-6-1 18:19:59', '%Y-%m-%d %H:%M:%S')
print(cday)
#2015-06-01 18:19:59

datetime转换为str

now = datetime.now()
print(now.strftime('%a, %b %d %H:%M'))
#Mon, May 05 16:28

datetime加减

  • 对日期和时间进行加减实际上就是把datetime往后或往前计算,得到新的datetime。加减可以直接用+和-运算符,不过需要导入timedelta这个类
from datetime import datetime, timedelta
now = datetime.now()


datetime(2023, 9, 13, 10, 30, 3, 540997)
print(now + timedelta(hours=10))#2023-09-13 20:38:44.709003

datetime(2023, 9, 13, 10, 30, 3, 540997)
print(now - timedelta(days=1))#2023-09-12 10:38:44.709003

datetime(2023, 9, 13, 10, 30, 3, 540997)
print(now + timedelta(days=2, hours=12))#2023-09-12 10:38:44.709003

本地时间转换为UTC时间

from datetime import datetime, timedelta, timezone

tz_utc_8 = timezone(timedelta(hours=8))  # 创建时区UTC+8:00
now = datetime.now()
print(now)

dt = now.replace(tzinfo=tz_utc_8)  # 强制设置为UTC+8:00
print(dt)

dt = datetime(2015, 9, 13, 10, 40, 13, 610986, tzinfo=timezone(timedelta(0, 28800)))
print(dt)

时区转换

from datetime import datetime, timedelta, timezone

# 拿到UTC时间,并强制设置时区为UTC+0:00:
utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc)
print(utc_dt)
# astimezone()将转换时区为北京时间:
bj_dt = utc_dt.astimezone(timezone(timedelta(hours=8)))
print(bj_dt)
# astimezone()将转换时区为东京时间:
tokyo_dt = utc_dt.astimezone(timezone(timedelta(hours=9)))
print(tokyo_dt)
# astimezone()将bj_dt转换时区为东京时间:
tokyo_dt2 = bj_dt.astimezone(timezone(timedelta(hours=9)))
print(tokyo_dt2)

小结

  • datetime表示的时间需要时区信息才能确定一个特定的时间,否则只能视为本地时间。

  • 如果要存储datetime,最佳方法是将其转换为timestamp再存储,因为timestamp的值与时区完全无关

base64

Base64是一种任意二进制转换文本字符串的编码方法,常用于在URL、Cookie、网页中传输少量二进制数据

  • Base64的原理很简单,首先,准备一个包含64个字符的数组:

    ['A', 'B', 'C', ... 'a', 'b', 'c', ... '0', '1', ... '+', '/']
    
  • 然后,对二进制数据进行处理,每3个字节一组,一共是3x8=24bit,划为4组,每组正好6个bit

    在这里插入图片描述

  • 这样我们得到4个数字作为索引,然后查表,获得相应的4个字符,就是编码后的字符串。

    • 所以,Base64编码会把3字节的二进制数据编码为4字节的文本数据,长度增加33%好处是编码后的文本数据可以在邮件正文、网页等直接显示。

    • 如果要编码的二进制数据不是3的倍数,最后会剩下1个或2个字节怎么办?

      • Base64用\x00字节在末尾补足后,再在编码的末尾上1个或2个=号,表示补了多少字节,解码的时候,会自动去掉

Python内置的base64可以直接进行base64的编解码:

import base64
#`b'str'`可以表示字节,
a = base64.b64encode(b'binary\x00string')
print(a)
b = base64.b64decode(b'YmluYXJ5AHN0cmluZw==')
print(b)
#b'YmluYXJ5AHN0cmluZw=='
#b'binary\x00string'
  • b'str'可以表示字节,

由于标准Base64编码后可能出现字符+和/,在URL中就不能直接作为参数,所以又有一种"url safe"的base64编码,其实就是把字符+和/分别变成-和_

#`b'str'`可以表示字节,
c= base64.b64encode(b'i\xb7\x1d\xfb\xef\xff')
print(c)#b'abcd++//'
d = base64.urlsafe_b64encode(b'i\xb7\x1d\xfb\xef\xff')
print(d)#b'abcd++//'
e = base64.urlsafe_b64decode('abcd--__')
print(e)#b'abcd++//'

hashlib

Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。

**什么是摘要算法呢?

  • **摘要算法又称哈希算法、散列算法。摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest目的是为了发现原始数据是否被人篡改过。(通常用16进制的字符串表示)。

  • 摘要算法之所以能指出数据是否被篡改过

    • 因为摘要函数是一个单向函数,计算f(data)很容易,但通过digest反推data却非常困难。而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同。

应用场景

  • 写了一篇文章,内容是一个字符串’how to use python hashlib - by Michael’,并附上这篇文章的摘要是’2d73d4f15c0db7f5ecb321b6a65e5d6d’。如果有人篡改了你的文章,并发表为’how to use python hashlib - by Bob’,你可以一下子指出Bob篡改了你的文章,因为根据’how to use python hashlib - by Bob’计算出的摘要不同于原始文章的摘要。

MD5是最常见的摘要算法,速度很快,生成结果是固定的128 bit/16字节,通常用一个32位的16进制字符串表示。如下所示

import hashlib
md5 = hashlib.md5()
md5.update('how to use md5 in python hashlib?'.encode('utf-8'))
print(md5.hexdigest())
#d26a53750bc40b38b65a520292f69306

如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的:

import hashlib

md5 = hashlib.md5()
md5.update('how to use md5 in '.encode('utf-8'))
md5.update('python hashlib?'.encode('utf-8'))
print(md5.hexdigest())
#d26a53750bc40b38b65a520292f69306

另一种常见的摘要算法是SHA1,调用SHA1和调用MD5完全类似:SHA1的结果是160 bit/20字节,通常用一个40位的16进制字符串表示。

import hashlib

sha1 = hashlib.sha1()
sha1.update('how to use sha1 in '.encode('utf-8'))
sha1.update('python hashlib?'.encode('utf-8'))
print(sha1.hexdigest())
#2c76b57293ce30acef38d98f6046927161b46a44

比SHA1更安全的算法是SHA256和SHA512,不过越安全的算法不仅越慢,而且摘要长度更长

hmac

通过哈希算法,我们可以验证一段数据是否有效,方法就是对比该数据的哈希值,例如,判断用户口令是否正确,我们用保存在数据库中的password_md5对比计算md5(password)的结果,如果一致,用户输入的口令就是正确的。

为了防止黑客通过彩虹表根据哈希值反推原始口令,在计算哈希的时候,不能仅针对原始输入计算,需要增加一个salt来使得相同的输入也能得到不同的哈希,这样,大大增加了黑客破解的难度。

  • 如果salt是我们自己随机生成的,通常我们计算MD5时采用md5(message + salt)。但实际上,把salt看做一个“口令”,加salt的哈希就是:计算一段message的哈希时,根据不同口令计算出不同的哈希。要验证哈希值,必须同时提供正确的口令。

    • 这实际上就是Hmac算法:Keyed-Hashing for Message Authentication。它通过一个标准算法,在计算哈希的过程中,把key混入计算过程中

    • 和我们自定义的加salt算法不同,Hmac算法针对所有哈希算法都通用,无论是MD5还是SHA-1。采用Hmac替代我们自己的salt算法,可以使程序算法更标准化,也更安全。

Python自带的hmac模块实现了标准的Hmac算法。我们来看看如何使用hmac实现带key的哈希。

import hmac
#原始数据
message = b'Hello, world!'
#密钥
key = b'secret'
h = hmac.new(key, message, digestmod='MD5')
# 如果消息很长,可以多次调用h.update(msg)
print(h.hexdigest())
#'fa4ee7d173f2d97ee79022d1a7355bcf'
  • 需要注意传入的key和message都是bytes类型,str类型需要首先编码为bytes

urllib

详见【Python】从入门到上头—网络请求模块urlib和reuests的应用场景(12)

XML

操作XML有两种方法:DOM和SAX

  • DOM会把整个XML读入内存,解析为树,因此占用内存大,解析慢,优点是可以任意遍历树的节点

  • SAX是流模式,边读边解析,占用内存小,解析快,缺点是我们需要自己处理事件

  • 正常情况下,优先考虑SAX,因为DOM实在太占内存。

在Python中使用SAX解析XML非常简洁,通常我们关心的事件是start_element,end_element和char_data,准备好这3个函数,然后就可以解析xml了。

如: 当SAX解析器读到一个节点时:

<a href="/">python</a>

会产生3个事件:

  • start_element事件,在读取<a href="/">时;

  • char_data事件,在读取python时;

  • end_element事件,在读取</a>时。

    from xml.parsers.expat import ParserCreate
    
    
    class DefaultSaxHandler(object):
        def start_element(self, name, attrs):
            print('sax:start_element: %s, attrs: %s' % (name, str(attrs)))
    
        def end_element(self, name):
            print('sax:end_element: %s' % name)
    
        def char_data(self, text):
            print('sax:char_data: %s' % text)
    
    
    xml = r'''<?xml version="1.0"?>
    <ol>
        <li><a href="/python">Python</a></li>
        <li><a href="/ruby">Ruby</a></li>
    </ol>
    '''
    
    handler = DefaultSaxHandler()
    parser = ParserCreate()
    #start_element事件
    parser.StartElementHandler = handler.start_element
    #end_element事件
    parser.EndElementHandler = handler.end_element
    #char_data事件
    parser.CharacterDataHandler = handler.char_data
    #解析
    parser.Parse(xml)
    

    执行结果

    sax:start_element: ol, attrs: {}
    sax:char_data: 
    
    sax:char_data:     
    sax:start_element: li, attrs: {}
    sax:start_element: a, attrs: {'href': '/python'}
    sax:char_data: Python
    sax:end_element: a
    sax:end_element: li
    sax:char_data: 
    
    sax:char_data:     
    sax:start_element: li, attrs: {}
    sax:start_element: a, attrs: {'href': '/ruby'}
    sax:char_data: Ruby
    sax:end_element: a
    sax:end_element: li
    sax:char_data: 
    
    sax:end_element: ol
    
    • 需要注意的是:读取一大段字符串时,CharacterDataHandler可能被多次调用,所以需要自己保存起来,在EndElementHandler里面再合并。

除了解析XML外,如何生成XML呢?

  • 99%的情况下需要生成的XML结构都是非常简单的,因此,最简单也是最有效的生成XML的方法是拼接字符串

    L = []
    L.append(r'<?xml version="1.0"?>')
    L.append(r'<root>')
    L.append(encode('some & data'))
    L.append(r'</root>')
    return ''.join(L)
    

HTMLParser

如果我们要编写一个搜索引擎,第一步是用爬虫把目标网站的页面抓下来,第二步就是解析该HTML页面,看看里面的内容到底是新闻、图片还是视频。

  • 假设第一步已经完成了,第二步应该如何解析HTML呢?

HTML本质上是XML的子集,但是HTML的语法没有XML那么严格,所以不能用标准的DOM或SAX来解析HTML。

Python提供了HTMLParser来非常方便地解析HTML,只需简单几行代码:

from html.parser import HTMLParser
from html.entities import name2codepoint

class MyHTMLParser(HTMLParser):

    def handle_starttag(self, tag, attrs):
        print('<%s>' % tag)

    def handle_endtag(self, tag):
        print('</%s>' % tag)

    def handle_startendtag(self, tag, attrs):
        print('<%s/>' % tag)

    def handle_data(self, data):
        print(data)

    def handle_comment(self, data):
        print('<!--', data, '-->')

    def handle_entityref(self, name):
        print('&%s;' % name)

    def handle_charref(self, name):
        print('&#%s;' % name)

parser = MyHTMLParser()
parser.feed('''<html>
<head></head>
<body>
<!-- test html parser -->
    <p>Some <a href=\"#\">html</a> HTML&nbsp;tutorial...<br>END</p>
</body></html>''')
  • feed()方法可以多次调用,也就是不一定一次把整个HTML字符串都塞进去,可以一部分一部分塞进去。

  • 特殊字符有两种,一种是英文表示的&nbsp;,一种是数字表示的&#1234;,这两种字符都可以通过Parser解析出来。

random

Python random 模块主要用于生成随机数。实现了各种分布的伪随机数生成器。

常用方法

andom()	生成一个 [0.0, 1.0) 之间的随机小数
seed(seed)	初始化给定的随机数种子
randint(a, b)	生成一个 [a, b] 之间的随机整数
uniform(a, b)	生成一个 [a, b] 之间的随机小数
choice(seq)	从序列 seq 中随机选择一个元素
shuffle(seq)	将序列 seq 中元素随机排列, 返回打乱后的序列

random.random()

import random
print(random.random())
#0.4784904215869241

**random.seed(seed) **

  • 初始化给定的随机数种子

  • 计算机使用确定性的算法计算出一个随机数序列。计算机产生的随机数并不真正的随机,但具有类似于随机数的统计特征,如均匀性、独立性等

  • 计算机根据随机数种子产生随机数序列,如果随机数种子相同,每次产生的随机数序列是相同的;如果随机数种子不同,产生的随机数序列是不同的。

    random.seed(10)
    a = random.randint(0, 100)
    print(a)
    a = random.randint(0, 100)
    print(a)
    a = random.randint(0, 100)
    print(a)
    # 73
    # 4
    # 54
    
    random.seed(10)
    a = random.randint(0, 100)
    print(a)
    a = random.randint(0, 100)
    print(a)
    a = random.randint(0, 100)
    print(a)
    # 73
    # 4
    # 54
    
    • 结果
    1个random.seed(10)设定种子为 10
    产生第 1 个随机数 73
    产生第 2 个随机数 4
    产生第 3 个随机数 542个random.seed(10)设定种子为 10
    产生第 1 个随机数 73
    产生第 2 个随机数 4
    产生第 3 个随机数 54
    
    可以看出,当种子相同时,产生的随机数序列是相同的
    

random.randint(a, b)

  • 生成一个 [a, b] 之间的随机整数,示例如下:

    a = random.randint(0, 2)
    print(a)
    a = random.randint(0, 2)
    print(a)
    a = random.randint(0, 2)
    print(a)
    # 1
    # 2
    # 0
    

random.uniform(a, b)

  • 是生成一个 [a, b] 之间的随机小数
    import random
    random.uniform(0, 2)
    #0.20000054219225438
    random.uniform(0, 2)
    #1.4472780206791538
    random.uniform(0, 2)
    #0.5927807855738692
    

random.choice(seq)

  • 从序列 seq 中随机选择一个元素

    import random
    seq = [1, 2, 3, 4]
    random.choice(seq)
    #3
    random.choice(seq)
    #1
    

random.shuffle(seq)

  • 将序列 seq 中元素随机排列, 返回打乱后的序列

    import random
    seq = [1, 2, 3, 4]
    random.shuffle(seq)
    #[1, 3, 2, 4]
    

小结

  • 利用HTMLParser,可以把网页中的文本、图像等解析出来。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1006619.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JSP ssm 网上求职管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 JSP ssm 网上求职管理系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采…

3900页手册415集视频426G资料迅为RK3568开发板

资料优势 专为3568编写|迅为原创|拒绝网络拼凑 20个手册2800页手册进行结构分层适用于学习与开发 为了方便大家清晰快速的学习&#xff0c;迅为iTOP-3568开发板手册资料全面升级&#xff0c;对手册内容进行了结构分层&#xff0c;共计20个文档&#xff0c;超2800页的资料专为…

sql注入之盲注总结

死在山野的风里&#xff0c;活在自由的梦里 sql注入之盲注总结 布尔 - 逻辑判断时间 - 延时判断报错 - 报错回显&#xff08;强制性报错 &#xff09;以DWVA靶场为例 盲注就是在注入的过程中&#xff0c;获取的数据不能显示到前端页面&#xff0c;此时&#xff0c;我们需要利用…

2023年武汉初级、中级、副高工程师职称评审条件是什么?甘建二告诉你

武汉中级职称评审通知已经出来了&#xff0c;武汉市中级、副高申报时间是8月31--9月18号&#xff0c;那么评这些职称需要满足什么条件呢&#xff1f;今天甘建二给大家分享一下评职称学历年限、专业等是怎么计算的&#xff0c;点赞收藏慢慢看。 一、武汉初级职称评审条件&#x…

【MySQL进阶】SQL性能分析

一、SQL性能分析 1.SQL执行频率 MySQL 客户端连接成功后&#xff0c;通过 show [session|global] status 命令可以提供服务器状态信 息。通过如下指令&#xff0c;可以查看当前数据库的 INSERT 、 UPDATE 、 DELETE 、 SELECT 的访问频次&#xff1a; -- session 是查看当…

jvm深入研究文档--整体概念

阿丹&#xff1a; 精通JVM对于一个java工程师非常重要&#xff0c;要是深入了解了jvm就可以有效的面对下面的问题 程序调优&#xff1a;JVM的配置和调优对于程序的运行有着至关重要的影响。不同的业务场景需要不同的JVM配置&#xff0c;比如设置不同的垃圾收集器、调整新生代和…

软考 - 计算机组成与体系笔记

数据的表示 进制转化 二进制转十进制&#xff08;十进制以D表示&#xff09; 从右往左&#xff0c;用二进制位上的数字乘以2的n次幂的和&#xff08;n从0开始1累加&#xff09; 十进制转二进制&#xff08;二进制以B表示&#xff09; 十进制数不断除以2直至到0&#xff0c;得…

电子智能充气泵pcba/芯片方案

智能充气泵是一种常见的气体压缩设备&#xff0c;它可以将空气或其他气体压缩成高压气体&#xff0c;用于充气、输送、压缩等工业和生活领域。智能充气泵的原理是利用机械或电动力量将气体压缩&#xff0c;使其体积减小&#xff0c;压力增大&#xff0c;从而达到充气的目的。电…

【echarts】如何将iconfont转换成echart所需的path路径 echarts折线图、柱状图如何设置自定义svg图标

步骤 下载iconfont图标到本地&#xff0c;用浏览器打开&#xff0c;右键查看源代码&#xff0c;或者用开发IDE软件打开&#xff0c;找到path d...&#xff0c;这个就是我们要传递给echart的icon的值。 代码示例&#xff1a; legend: {data: data?.map((item) > item.comp…

Fiddler抓http数据

目录 参考博客 一、Fiddler配置二、分析Http请求1. Http消息结构简介1.1 Request请求消息1.2 Response响应消息 2. 分析Get接口2.1 请求示例2.2 查看Get请求2.3 查看Get响应 3 分析Post接口 参考博客 一、Fiddler配置 首先需要对Fiddler抓取Https请求进行相关配置&#xff1a…

【九章斩题录】C/C++:判定字符是否唯一

精品题解 &#x1f525; 《九章斩题录》 &#x1f448; 猛戳订阅 面试题 01.01. 判定字符是否唯一 ✅ 模板&#xff1a;C语言 class Solution { public:bool isUnique(string astr) {} }; &#x1f4ad; 思考&#xff1a;《程序员面试金典》里的题&#xff0c;这题和剑指Off…

typescript错误代码 error TS2451: 无法重新声明块范围变量“age”。ts(2451)

今天心血来潮写ts教程的时候发现一个问题,如下 短短的两行代码,竟然都报错,无法重新声明块范围变量age\。明明与其他文件没有相互依赖&#xff0c;却会提示 [ts] 无法重新声明块范围变量“age”。。且该文件目录夹下&#xff0c;也没有其他文件。为什么会有这个报错呢&#xff…

NZ系列工具NZ03:利用右键进行筛选操作

【分享成果&#xff0c;随喜正能量】生活就是这样&#xff0c;别人看的是结果&#xff0c;而自己撑的却是整个过程。曾经的微笑&#xff0c;是一种心情&#xff0c;现在的微笑&#xff0c;只不过是一种表情。如果情绪不能用言语说出来&#xff0c;那就去吹吹风吧。。 我的教程…

Python爬虫被封ip的解决方案

目录 一、网站反爬虫机制有哪些 二、Python爬虫被封ip的原因 三、爬虫被封IP怎么解决 四、代码示例 在爬虫程序运行过程中&#xff0c;被封禁IP地址是常见的问题之一。这通常是由于目标网站采取了反爬虫机制&#xff0c;例如限制单个IP地址的请求频率或识别请求特征等。当爬…

-60V -40V -100V 30A 50A 100A P管大电流 正极,负极做关断的电路图 解决方案N沟道,P沟道MOSFET开关电路图介绍

P沟道MOS管工作原理以及参数&#xff1f;中广芯源提供原理图纸&#xff0c;估计对需求者有帮助。 P沟道MOS管工作原理&#xff1a;金属氧化物半导体场效应(MOS)晶体管可分为N沟道与P沟道两大类&#xff0c; P沟道硅MOS场效应晶体管在N型启衡旅硅衬底悄凳上有两个P区&#xff0…

【80天学习完《深入理解计算机系统》】第十五天 4.1 Y86-64指令集与Verilog HDL

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

【GNN 03】PyG

工具包安装&#xff1a; 不要pip安装 https://github.com/pyg-team/pytorch_geometrichttps://github.com/pyg-team/pytorch_geometric import torch import networkx as nx import matplotlib.pyplot as pltdef visualize_graph(G, color):plt.figure(figsize(7, 7))plt.xtic…

10分钟学会Hive之用户自定义函数UTF开发

1. 用户自定义函数概述 用户自定义函数简称UDF&#xff0c;源自于英文user-defined function。自定义函数总共有3类&#xff0c;是根据函数输入输出的行数来区分的&#xff0c;分别是&#xff1a; UDF&#xff08;User-Defined-Function&#xff09;普通函数&#xff…

Excel 公式函数:学习基本示例

数据准备 对于本教程&#xff0c;我们将使用以下数据集。 家居用品预算 S / N项目数量价格小计价格适中吗&#xff1f;1芒果96002橘子312003番茄125004食用油565005汤力水133900 房屋建筑项目时间表 S/NITEM开始日期结束日期持续时间&#xff08;天&#xff09;1调查土地0…

C++项目实战——基于多设计模式下的同步异步日志系统-⑧-日志落地类设计

文章目录 专栏导读抽象基类StdoutSink类设计FileSink类设计RollBySizeSink类设计日志落地工厂类设计日志落地类整理日志落地拓展测试RollByTimeSink类设计测试代码测试完整代码 专栏导读 &#x1f338;作者简介&#xff1a;花想云 &#xff0c;在读本科生一枚&#xff0c;C/C领…