压缩算法LZ4

news2024/11/19 10:20:08

LZ4简介

LZ4 是无损压缩算法,提供每个核 大于 500 MB/s 的压缩速度,可通过多核 CPU 进行扩展。LZ4算法解压速度极快,单核解压速度达到GB/s,通常达到多核系统的 RAM 速度限制。

压缩速度可以动态调整,选择一个“加速”因子,牺牲压缩比以获得更快的速度。另外还提供了一个高压缩率函数LZ4_HC,牺牲压缩时间换取更高的压缩比,但解压缩速度不会受影响。

LZ4实现了两种格式:

  • lz4_Block_format:原始LZ4块压缩格式

  • lz4_Frame_format:用于压缩任意大的数据流,或压缩任意大小的文件

Benchmarks

从官方提供的Benchmarks数据,可以看出**LZ4 default (v1.9.0)LZ4 HC -9 (v1.9.0)**压缩率和压缩速度不一致,但是解压缩速度却相同。

CompressorRatioCompressionDecompression
memcpy1.00013700 MB/s13700 MB/s
LZ4 default (v1.9.0)2.101780 MB/s4970 MB/s
LZO 2.092.108670 MB/s860 MB/s
QuickLZ 1.5.02.238575 MB/s780 MB/s
Snappy 1.1.42.091565 MB/s1950 MB/s
[Zstandard] 1.4.0 -12.883515 MB/s1380 MB/s
LZF v3.62.073415 MB/s910 MB/s
[zlib] deflate 1.2.11 -12.730100 MB/s415 MB/s
LZ4 HC -9 (v1.9.0)2.72141 MB/s4900 MB/s
[zlib] deflate 1.2.11 -63.09936 MB/s445 MB/s

LZ4 Block Format

LZ4 是一种 LZ77 型压缩器,具有固定的、面向字节的编码格式,

块格式

LZ4压缩块由序列组成。分为三个区域:

  • Literals:指没有重复、首次出现的字节流,即不可压缩的部分
  • Match:指重复项,可以压缩的部分
  • Token:记录literal长度,match长度。

LZ4格式

简单的示例如下:

输入:abcde_bcdefgh_abcdefghxxxxxxx
输出:tokenabcde_(5,4)fgh_(14,5)fghxxxxxxx
格式:[token]literals(offset,match length)[token]literals(offset,match length)....

Token

令牌。一个字节,划分两个4位的字段:高4位为字面长度(Literal length),低4位为匹配长度(Match length)。

  • 高4位:4个位只能表示0-15,再多的话就需要再增加一些字节(高4位为15表示需要增加接下来字节),每个增加的字节可表示0-255。如果为255,表示还有增加一个字节,直到字节中不满255。因此没有大小限制。举例如下:

    字面长度为48表示:Token高4位为15,下一字节为33(48-15);

    字面长度为280表示:Token高4位为15,下一字节为255,再下一字节为10(280-15-255);

    字面长度为15表示:Token高4位为15,下一字节为0(必须输出零,15-15);

  • 低4位:同理高4位,只是匹配长度放在offset之后

Literal length

字面长度字段,0-n字节

Literals

字面量本身字段,字面量可能为0

Offset

两字节的偏移量,小端格式,表示匹配到向前偏移长度。例如3表示当前位置向前有3个数据是匹配的(重复的)。最大值offset为 65535,65536 及以上无法编码。请注意,0 是无效的偏移值。这种值的存在表示无效(损坏)块。

Match length

匹配长度字段,0-n字节。注意这里的0意味着复制操作将是最小的,即匹配的最小长度minmatch为4(Token低4位+4才为match length)。因此 0 值表示 4 个字节,15 值表示 19+ 个字节。

结束块限制

结束块有一些特定限制:

  1. 最后一个序列只包含字面量。
  2. 输入的最后 5 个字节始终是字面量。输入的最后 5 个字节始终是文字。
    • 特别地:如果输入小于 5 个字节,则只有一个序列,它包含整个输入作为字面量。空输入可以用零字节表示,解释为没有字面量和匹配的最终标记。
  3. 最后一个匹配必须在块结束前至少 12 个字节开始。最后一场比赛是倒数第二场比赛的一部分。紧随其后的是最后一个序列,它只包含字面量。
    • 请注意,因此,不能压缩 < 13 字节的独立块,因为匹配必须复制“某些东西”,因此它至少需要一个前字节。
    • 但是,当一个块可以引用另一个块的数据时,它可以立即以匹配而不是字面量开始,因此可以压缩正好 12 个字节的块。

当一个块不遵守这些结束条件时,允许一致的解码器将该块视为不正确而拒绝。

这些规则是为了确保与各种历史解码器的兼容性,这些解码器在面向速度的设计中依赖这些条件。

LZ4 Frame Format

介绍

定义一种无损压缩数据格式,与CPU类型、操作系统、文件系统和字符集无关,适合文件压缩,管道和流压缩。

对于任意长度顺序呈现的输入数据流,支持部分数据的压缩和解压,因此可以用于数据通信。该格式使用 LZ4 压缩方法和xxHash-32 校验(可选,用于检测数据损坏)。

定义的数据格式不允许随机访问压缩数据。

一般结构

MagicNbF. DescriptorBlock(…)EndMarkC. Checksum
4 bytes3-15 bytes4 bytes0-4 bytes
  • MagicNb:Magic Number,魔法数,4字节,小端,值为0x184D2204

  • F. Descriptor:Frame Descriptor,帧描述符,3-15字节,最为重要,Magic_Number 和_Frame_Descriptor_放在一起常叫做LZ4 Frame Header,长度为7-19字节

  • Block:Data Blocks,数据块,存放的压缩数据

  • EndMark:结束标记,在最后一个数据块之后,值为32位的0x00000000

  • C.Checksum:Content Checksum,内容校验和验证这个数据内容是否已正确解码。其是xxHash-32 算法计算的摘要值,该算法使用原始数据(解码后)作为输入,0作为种子。只有在帧描述符Frame Descriptor中设置了相关标志时,才会出现Content_Checksum。Content_Checksum用于验证:所有块都以正确的顺序完成传输,没有错误,编码/解码过程没有产生失真。推荐使用它EndMarkContent_Checksum放在一起常叫做LZ4 Frame Footer,长度为4-8字节

  • Frame Concatenation:在某些情况下,最好附加多个帧,例如为了将新数据添加到现有压缩文件而不重新构建它。在这种情况下,每个帧都有自己的一组描述符标志。每个帧都被认为是独立的,帧之间的唯一关系是它们的顺序。在单个流或文件中解码多个连接帧的能力不在LZ4规范范围内。

Frame Descriptor

FLGBD(Content Size)(Dictionary ID)HC
1 byte1 byte0 - 8 bytes0 - 4 bytes1 byte

描述符使用最少 3 个字节,最多 15 个字节,具体取决于可选参数。

FLG byte

BitNb7-6543210
FieldNameVersionB.IndepB.ChecksumC.SizeC.ChecksumReservedDictID
  • Version:版本号。占两位,必须设置为01
  • B.Indep:Block Independence flag,块独立标志。如果为1,则块是独立的,否则为0,每个块都依赖于先前的块(最大 LZ4 窗口大小,即 64 KB)。在这种情况下,有必要按顺序解码所有块。块相关性提高了压缩率,尤其是对于小块。但是另一方面,将无法随机访问或多线程解码。
  • B.Checksum:Block checksum flag,块校验标志。如果为1,则每个数据块后面跟一个4字节的checksum,通过对原始(压缩后)数据块使用 xxHash-32 算法计算得出,目的是在解码之前立即检测数据损坏(存储或传输错误)。B.Checksum块校验和的使用是可选的。
  • C.Size:Content Size flag,块大小标志。如果为1,则BD之后放未压缩的数据大小字段,其是 8 字节无符号小端值的形式。C.Size也是可选的。
  • C.Checksum:Content checksum flag,内容校验和标志。如果为1,在EndMark之后添加32位的内容校验和。
  • DictID:Dictionary ID flag,字典ID标志。如果为1,在Content Size之后,放4字节的Dict-ID。

BD byte

BitNb76-5-43-2-1-0
FieldNameReservedBlock MaxSizeReserved
  • Block MaxSize:Block Maximum Size,块最大长度。该信息有助于解码器分配内存。这里的大小是指原始(未压缩)数据大小的最大值。块最大大小是下表中的一个值:

    01234567
    N/AN/AN/AN/A64 KB256 KB1 MB4 MB

    解码器可能拒绝分配比较大的的块空间。

  • Reserverd:保留位,必须为0

Content Size bytes

这是原始(未压缩)大小。此信息是可选的,并且仅在设置了相关标志时才出现。内容大小使用无符号 8 字节提供,最大为 16EB容量。格式为小端。此值通常用于显示或内存分配。它可以被解码器跳过,或用于验证内容的正确性。

Dictionary ID

仅当设置了相应标志时才存在字典 ID。它是一个无符号的 32 位值,使用 little-endian 约定存储。字典对于压缩短输入序列很有用。压缩器可以利用字典上下文以更紧凑的方式对输入进行编码。它作为一种“已知前缀”工作,压缩器和解压缩器都使用它来“预热”参考表。

解压缩器可以使用 Dict-ID 标识符来确定必须使用哪个字典才能正确解码数据。压缩器和解压缩器必须使用完全相同的字典。假定 32 位 dictID 唯一标识一个字典。

在单个框架内,可以定义单个字典。当帧描述符定义独立的块时,每个块都将使用相同的字典进行初始化。如果帧描述符定义了链接块,则字典只会在帧开始时使用一次。

HC byte

  • hc:Header Checksum,头校验和。其是Frame Descriptor的校验和,值为xxh32(使用0为种子)的第二字节:(xxh32()>>8) & 0xFF。头检验和检验描述符是否正确,头校验和是信息性的,可以跳过

Data Blocks

Block Sizedata(Block Checksum)
4 bytes0 - 4 bytes

Block Size

占用4字节,小端格式。如果最高位为1,该块未压缩;最高位为0,则使用LZ4 块格式规范对块进行 LZ4 压缩。其他位是数据段的长度大小(以字节为单位),该大小不包括校验和(如果存在)。

Block_Size不得大于Block_Maximum_Size。如果源数据不可压缩,可能存在Block_Size等于Block_Maximum_Size。在这种情况下,必须使用未压缩格式传递此类数据块。

0x00000000无效,而是表示EndMark。请注意,这与 (最高位设置为1) 的值不同0x80000000,后者是大小为 0(空)的未压缩块,它是有效的,因此不会结束帧。请注意,如果启用了Block_checksum,则即使是空块也必须后跟 32 位块校验和。

Data

要解码的实际数据所在的位置。它可能会被压缩,也可能不会被压缩,这取决于之前的字段指示。压缩时,数据必须遵守LZ4 块格式规范。请注意,块不一定是满的。未压缩的数据大小可以是最大Block_Maximum_Size,因此它包含的数据可能少于最大块大小。

Block Checksum

仅在设置了相关标志时才存在。这是一个 4 字节的校验和值,采用小端格式,使用xxHash-32 算法对原始(未解码)数据块进行计算,种子为零,目的是在解码之前检测数据损坏(存储或传输错误)。

Skippable Frames

Magic NumberFrame SizeUser Data
4 bytes4 bytes

可跳过的帧,其允许将用户定义的数据集成到串联的帧流中。它的设计非常简单,唯一的目标是让解码器快速跳过用户定义的数据并继续解码。

为了便于识别,不鼓励使用可跳过的帧开始连接帧流。如果需要在可跳过帧中使用一些用户数据,建议从零字节 LZ4 帧开始,然后是可跳过帧,将使文件类型标识符更容易。

Magic Number

魔法数,4字节,小端格式。值为0x184D2A5X,表示从 0x184D2A50 到 0x184D2A5F 的任何值。所有 16 个值都可用于识别可跳过的帧。

Frame Size

这是接下来用户数据的大小(以字节为单位)(不包括魔法数或大小字段本身)。4 字节,小端格式,无符号 32 位。这意味着用户数据不能大于 (232-1) 字节。

User Data

用户数据,解码器会跳过这些数据。

压缩示例

数据原文

hello david, hello lily, hello tom, hello lucy, hello bob

保存到文件data

$ echo "hello david, hello lily, hello tom, hello lucy, hello bob" > data

压缩前数据

数据原文的hex形式如下。

$ hexdump -C data
00000000  68 65 6c 6c 6f 20 64 61  76 69 64 2c 20 68 65 6c  |hello david, hel|
00000010  6c 6f 20 6c 69 6c 79 2c  20 68 65 6c 6c 6f 20 74  |lo lily, hello t|
00000020  6f 6d 2c 20 68 65 6c 6c  6f 20 6c 75 63 79 2c 20  |om, hello lucy, |
00000030  68 65 6c 6c 6f 20 62 6f  62 0a                    |hello bob.|
0000003a

压缩后数据

使用帧格式,执行lz4命令进行压缩如下。

$ lz4 data data.lz4

数据显示如下。

$ hexdump -C data.lz4
00000000  04 22 4d 18 64 40 a7 29  00 00 00 d2 68 65 6c 6c  |."M.d@.)....hell|
00000010  6f 20 64 61 76 69 64 2c  20 0d 00 44 6c 69 6c 79  |o david, ..Dlily|
00000020  0c 00 34 74 6f 6d 0b 00  34 6c 75 63 17 00 50 20  |..4tom..4luc..P |
00000030  62 6f 62 0a 00 00 00 00  90 ba d9 c9              |bob.........|
0000003c

数据分析

MagicNb

04 22 4D 18

魔法数为0x184D2204

F. Descriptor

64 40 a7
FLGBD(Content Size)(Dictionary ID)HC
64401 byte
  • FLG:0x64=0110 0100

    7-6543210
    VersionB.IndepB.ChecksumC.SizeC.ChecksumReservedDictID
    01100100
    版本01块独立无Block校验无块大小有内容校验保留无字典ID
  • BD:0x40,块最大大小为1MB

  • Content Size:无

  • Dictionary ID:无

  • HC:0xa7

Block

00000007  29 00 00 00 d2 68 65 6c  6c 6f 20 64 61 76 69 64  |)....hello david|
00000017  2c 20 0d 00 44 6c 69 6c  79 0c 00 34 74 6f 6d 0b  |, ..Dlily..4tom.|
00000027  00 34 6c 75 63 17 00 50  20 62 6f 62 0a           |.4luc..P bob.|
00000034
Block Sizedata(Block Checksum)
4 bytes0 - 4 bytes
0x00000029d2 68 65 6c … 62 6f 62 0a
  • Block Size:0x00000029,最高为0,表示压缩,data长度为0x29=41

  • data:41字节的压缩数据

    0000000b  d2 68 65 6c 6c 6f 20 64  61 76 69 64 2c 20 0d 00  |.hello david, ..|
    0000001b  44 6c 69 6c 79 0c 00 34  74 6f 6d 0b 00 34 6c 75  |Dlily..4tom..4lu|
    0000002b  63 17 00 50 20 62 6f 62  0a                       |c..P bob.|
    00000034
    

    LZ4格式

    1. 序列1

      d2 68 65 6c 6c 6f 20 64  61 76 69 64 2c 20 0d 00
      
      • Token:0xd2,字面长度0x0d,匹配长度0x02(实际为0x06)

      • Literals:字面量13字节

        68 65 6c 6c 6f 20 64 61 76 69 64 2c 20
        
      • Offset:0x000d,向前偏移13字节

    2. 序列2

      44 6c 69 6c 79 0c 00
      
      • Token:0x44,字面长度0x04,匹配长度0x04(实际为0x08)

      • Literals:字面量4字节

        6c 69 6c 79
        
      • Offset:0x000c,向前偏移12字节

    3. 序列3

      37 74 6f 6d 0b 00
      
      • Token:0x34,字面长度0x03,匹配长度0x04(实际为0x08)

      • Literals:字面量3字节

        74 6f 6d
        

        Offset:0x000b,向前偏移11字节

    4. 序列4

      34 6c 75 63 17 00
      
      • Token:0x34,字面长度0x03,匹配长度0x04(实际为0x08)

      • Literals:字面量3字节

        6c 75 63
        

        Offset:0x0017,向前偏移23字节

    5. 序列5(最后一个序列)

      50 20 62 6f 62 0a
      
      • Token:0x50,字面长度0x05,匹配长度0x00

      • Literals:字面量5字节

        20 62 6f 62 0a
        
  • Block Checksum:无

EndMark

00 00 00 00

结束标识0x00000000

C. Checksum

90 ba d9 c9
 - Literals:字面量3字节

   ```bash
   6c 75 63
   ```

   Offset:0x0017,向前偏移23字节
  1. 序列5(最后一个序列)

    50 20 62 6f 62 0a
    
    • Token:0x50,字面长度0x05,匹配长度0x00

    • Literals:字面量5字节

      20 62 6f 62 0a
      
  • Block Checksum:无

EndMark

00 00 00 00

结束标识0x00000000

C. Checksum

90 ba d9 c9

欢迎关注“安全有理”微信公众号。

安全有理

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

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

相关文章

VLOOKUP函数在表格的简单运用-两个表匹配

1.什么是VLOOKUP&#xff1f; VLOOKUP是Excel中的一个内置函数&#xff0c;主要用于在区域或表格的首列查找指定的值&#xff0c;并返回该行中其他列的值。它特别适用于跨表格数据匹配 2.函数运用 2.1.这边两个表取名a表和b表&#xff0c;做为我们的实例表。 表格a包含&…

windows环境下创建python虚拟环境

windows环境下创建python虚拟环境 使用virtualenv库创建虚拟环境&#xff0c;可使不同的项目处于不同的环境中 安装方法&#xff1a; pip install virtualenv -i https://pypi.tuna.tsinghua.edu.cn/simple pip install virtualenvwrapper-win -i https://pypi.tuna.tsinghua…

git 还原被删除的分支

在多人项目开发中&#xff0c;有一次碰到忘记合并到master分支了&#xff0c;直接就把开发分支给删除了&#xff0c;现在记录下怎么还原被删除的分支 必须保证删除的分支之前已经被推送到了远程仓库 # 找出被删除分支的最后一个提交的哈希值 git reflog show# 找到提交哈希值…

【数据结构】(C语言):队列

队列&#xff1a; 线性的集合。先进先出&#xff08;FIFO&#xff0c;first in first out&#xff09;。两个指针&#xff1a;头指针&#xff08;指向第一个进入且第一个出去的元素&#xff09;&#xff0c;尾指针&#xff08;指向最后一个进入且最后一个出去的元素&#xff0…

虚拟机启动失败 请进行修复 关闭hyper-v

场景 win11开启夜神模拟器时弹出此提示。点击关闭hyper-v并重启电脑后仍然不行。 解决方法 关闭 Windows安全中心 的 内存完整性 后重启电脑恢复正常。 补充 由于我这里除了会用到夜神模拟器&#xff0c;还会用到docker&#xff0c;而docker又依赖hyper-v&#xff0c;不…

PHP基础教程——总结W3school

1、<?php ?> 2、$ 声明变量 3、变量大小写敏感 关键字&#xff08;if、else、echo&#xff09;和用户定义的类、函数大小写不敏感 4、三种注释 // # /* */ 5、echo "<br>"; 换行 6、global(关键字) 函数内访问全局变量 $GLOBALS[index] …

三坐标测量机的“柔性”特点及其在工业中的应用

现代制造业中&#xff0c;三坐标测量机&#xff08;CMM&#xff09;在产品开发、质量控制和生产过程中发挥着重要作用。它通过高精度准确测量工件的几何尺寸和形状&#xff0c;来保证产品质量符合严格的技术规范。CMM高精度和高效率的特点使其成为自动化生产线和质量控制流程中…

统一的可观察性和安全性如何增强你的业务?

作者&#xff1a;来自 Elastic Michael Calizo 利用人工智能、异常检测和增强攻击发现功能&#xff0c;在一个平台上增强组织的可观察性和安全性能力 当今数字环境中的组织越来越关注服务可用性&#xff0c;并保护其软件免受恶意篡改和攻击。传统的安全和可观察性工具通常以孤…

SpringMVC的架构有什么优势?——控制器(一)

文章目录 控制器(Controller)1. 控制器(Controller)&#xff1a;2. 请求映射(Request Mapping)&#xff1a;3. 参数绑定(Request Parameters Binding)&#xff1a;4. 视图解析器(View Resolver)&#xff1a;5. 数据绑定(Data Binding)&#xff1a;6. 表单验证(Form Validation)…

阿里云物联网应用层开发:第一部分,项目简介

文章目录 1、物联网应用层简介2、阿里云物联网应用层开发例程主要内容3、需要掌握基础知识 1、物联网应用层简介 应用层是物联网系统的用户界面&#xff0c;它提供了用户与系统交互的接口&#xff0c;这一层是将网络传输层的数据结果以易于理解和使用的方式呈现给用户&#xf…

企业互联网建站源码系统 附带完整的安装代码包以及搭建部署教程

系统概述 企业互联网建站源码吸系统是一款集众多先进功能于一身的建站工具。它提供了丰富的模板和组件&#xff0c;允许企业根据自身需求和品牌形象进行个性化定制&#xff0c;快速搭建出具有独特风格的网站。 代码示例 系统特色功能一览 1.用户友好界面&#xff1a;系统采用…

传感器的静态标定

1.传感器静态标定的基本概念 传感器的静态标定指标主要有线性度、灵敏度、重复性、灵敏度等。 &#xff08;1&#xff09;线性度 线性度是描述传感器静态特性的一个重要指标&#xff0c;以被测输入量处于稳定状态为前提。在规定条件下&#xff0c;传感器校准曲线与拟合直线间…

AI音乐革命:创新的门槛降低与产业未来的挑战

文章目录 每日一句正能量前言整体介绍人机合作AI在音乐创作中的辅助作用人机共同创作的模式实现人机共同创作的可能性伦理和法律考量 伦理道德AI与人类创造力的关系技术发展与人类创造力的平衡社会和文化影响结论 后记AI与音乐的未来交响创新的双刃剑版权与伦理的探讨人机合作的…

Centos7安装Minio笔记

一、Minio概述 Minio是一款开源的对象存储服务器&#xff0c;可以运行在多种操作系统上&#xff0c;包括Linux、Windows和MacOS等。提供一种简单、可扩展、高可用的对象存储解决方案&#xff0c;支持多种数据格式&#xff0c;包括对象、块和文件等。Minio是一款强大、灵活、可…

js基础学习

1、js概述 js是javascript的简称&#xff0c;作用是实现页面和用户的交互 js由浏览器解析运行&#xff0c;不需要编译 js由es基础语法&#xff0c;bom浏览器相关&#xff0c;dom文档操作相关 三大部分组成 2、html引入js <!DOCTYPE html> <html lang"zh-CN&qu…

鸿蒙 DevEcho Studio 查看设备文件

在菜单栏单击View > Tool Windows > Device File Browser&#xff0c;打开Device File Browser。 从下拉列表中选择设备&#xff08;设备需已连接&#xff09;。 选择设备后&#xff0c;显示文件/文件夹列表&#xff0c;可进行以下操作&#xff1a; 右键单击目录…

24 年程序员各岗位薪资待遇汇总(最新)

大家好&#xff0c;我是程序员鱼皮。今天分享 24 年 6 月最新的程序员各岗位薪资待遇汇总。 数据是从哪儿来的呢&#xff1f;其实很简单&#xff0c;BOSS 直聘上有一个免费的薪酬查询工具&#xff0c;只要认证成为招聘者就能直接看&#xff0c;便于招聘者了解市场&#xff0c;…

【操作与配置】Xshell安装使用

Xshell是一款功能强大的远程管理工具&#xff0c;主要用于通过SSH&#xff08;Secure Shell&#xff09;、TELNET等协议连接和管理远程服务器。它支持多种会话管理、脚本编写、端口转发等功能&#xff0c;适合系统管理员和开发者使用。 安装 官网下载&#xff1a;家庭/学校免费…

咖啡消费旺季到来 为何想转让的库迪联营商却越来越多

文 | 智能相对论 作者 | 霖霖 去年还在朝“三年万店”计划狂奔的库迪&#xff0c;今年已出现明显“失速”。 早在今年2月&#xff0c;库迪就官宣其门店数已超过7000家&#xff0c;如今4个多月过去&#xff0c;据极海品牌监测数据显示&#xff0c;截至6月27日&#xff0c;其总…

【日记】度过了一个堕落的周末……(184 字)

正文 昨天睡了一天觉&#xff0c;今天看了一天《三体》电视剧。真是堕落到没边了呢&#xff08;笑。本来想写代码完成年度计划&#xff0c;或者多写几篇文章&#xff0c;但实在不想写&#xff0c;也不想动笔。 感觉这个周末什么都没做呢&#xff0c;休息倒是休息好了。 今天 30…