You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用lz4.frame压缩多文件时解压出现UnicodeDecodeError问题求助

文件归档/解压时元数据解析错误问题修复

问题现象

使用lz4.frame压缩多文件并写入元数据(文件名长度、文件名、文件大小)后,第一个文件可正常解压,但第二个文件读取到的文件名长度错误(变为29742,实际应为9),进而触发UnicodeDecodeError——因为读取的内容包含了压缩数据而非文件名。

压缩输出:

file name length 9
file name file1.txt
file size 762
file name length 9
file name file2.txt
file size 1105
file name length 9
file name file3.txt
file size 1472

解压输出:

file name length 9
file name file1.txt
file size 762
file name length 29742
Traceback (most recent call last):
File "d:\Code Playground\Python\fileSharing\fileSharing (2).py", line 250, in
decompression("archive.lz4")
File "d:\Code Playground\Python\fileSharing\fileSharing (2).py", line 166, in decompression
file_name = archive.read(file_name_length).decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc5 in position 167: invalid continuation byte

核心原因

压缩时未记录压缩后数据的长度,解压阶段无法确定当前文件的压缩数据何时结束,错误地使用archive.read()读取所有剩余内容(包含下一个文件的元数据)作为当前文件的压缩数据。解压后指针未正确定位到下一个文件的元数据起始位置,导致后续读取的元数据是压缩数据的一部分,解析出错误的文件名长度。

解决方案

1. 修改压缩逻辑:添加压缩数据长度记录

在写入原始文件大小后,追加写入压缩后数据的长度,确保解压时能精确读取对应长度的压缩数据。

修改后的压缩代码:

import os
import struct
import lz4.frame

def compression(file_paths, archive_path):
    with open(archive_path, 'wb') as archive:
        for file_path in file_paths:
            file_name = os.path.basename(file_path)
            file_name_bytes = file_name.encode('utf-8')
            file_name_length = len(file_name_bytes)
            
            # 写入文件名长度(指定小端字节序,跨平台兼容)
            archive.write(struct.pack('<i', file_name_length))
            # 写入文件名
            archive.write(file_name_bytes)
            
            # 读取原始文件并压缩
            with open(file_path, 'rb') as f:
                raw_data = f.read()
                compressed_data = lz4.frame.compress(raw_data)
            
            raw_size = len(raw_data)
            compressed_size = len(compressed_data)
            
            # 写入原始文件大小
            archive.write(struct.pack('<i', raw_size))
            # 写入压缩后数据长度
            archive.write(struct.pack('<i', compressed_size))
            # 写入压缩数据
            archive.write(compressed_data)
            
            # 打印日志(可选)
            print(f"file name length {file_name_length}")
            print(f"file name {file_name}")
            print(f"file size {raw_size}")

2. 修改解压逻辑:按记录的长度读取压缩数据

读取完原始文件大小后,先读取压缩数据长度,再读取对应长度的字节作为压缩数据,确保指针精确移动到下一个文件的元数据位置。

修改后的解压代码:

import struct
import lz4.frame

def decompression(archive_path):
    with open(archive_path, 'rb') as archive:
        while True:
            # 读取文件名长度
            fname_len_data = archive.read(4)
            if not fname_len_data:
                break  # 归档文件读取完毕
            
            file_name_length = struct.unpack('<i', fname_len_data)[0]
            # 读取文件名
            file_name = archive.read(file_name_length).decode('utf-8')
            # 读取原始文件大小
            raw_size_data = archive.read(4)
            raw_size = struct.unpack('<i', raw_size_data)[0]
            # 读取压缩数据长度
            comp_size_data = archive.read(4)
            compressed_size = struct.unpack('<i', comp_size_data)[0]
            
            # 打印日志(可选)
            print(f"file name length {file_name_length}")
            print(f"file name {file_name}")
            print(f"file size {raw_size}")
            
            # 读取指定长度的压缩数据
            compressed_data = archive.read(compressed_size)
            # 解压数据
            decompressed_data = lz4.frame.decompress(compressed_data)
            
            # 校验解压后数据长度(可选,增强可靠性)
            if len(decompressed_data) != raw_size:
                print(f"警告:{file_name}解压后长度与原始大小不符")
            
            # 写入输出文件
            with open(file_name, 'wb') as output_file:
                output_file.write(decompressed_data)

额外注意事项

  • 使用<i指定小端字节序,避免不同平台(如Windows/Linux)间的整数解析错误
  • 用len(raw_data)获取原始文件大小,比os.path.getsize更可靠,避免文件读取前被修改导致的不一致
  • 可选添加解压后长度校验,及时发现数据损坏或归档错误

内容的提问来源于stack exchange,提问作者Sajjad Ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 04:47:01