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

使用pycurl解压lz4压缩OS镜像写入磁盘时分区调整报错求助

问题:pycurl流式解压LZ4镜像写入磁盘导致分区表损坏

使用pycurl获取OS镜像并流式解压写入磁盘时,GZIP格式处理正常,但LZ4格式写入后调整分区大小出现以下错误:

条目大小为0字节,但本程序仅支持128字节的条目。
已相应调整,但分区表可能已损坏。
警告:分区表表头声明分区表条目大小为0字节,但本程序仅支持128字节的条目。
已相应调整,但分区表可能已损坏。
正在内存中创建新的GPT条目。
操作已成功完成。
错误:分区不存在

通过io.BytesIO全量缓存后解压再写入的方式可以正常工作,代码如下:

if url.endswith('.lz4'):
    with io.BytesIO() as output_buffer:
        curl.setopt(pycurl.WRITEDATA, output_buffer)
        curl.perform()
        output_buffer.seek(0)
        decompressed_data = lz4.frame.decompress(output_buffer.read())
        disk.write(decompressed_data)

但希望实现流式处理避免全量缓存,尝试的代码未成功:

def write_to_disk(self, url, dev, proxy=None):

    if os.path.isfile(dev):
        size = os.path.getsize(dev)

    with open(os.path.realpath(dev), 'wb') as disk:
        disk.seek(0)

        def write_gz(buf):
            disk.write(d.decompress(buf))

        def write_lz4(buf):
            disk.write(lz4.decompress(buf))

        try:
            curl = pycurl.Curl()
            curl.setopt(pycurl.URL, url)
            if proxy is not False:
                curl.setopt(pycurl.PROXY, proxy)
            curl.setopt(pycurl.BUFFERSIZE, 1024)
            if url.endswith('.lz4'):
                curl.setopt(pycurl.WRITEFUNCTION, write_lz4)
            elif url.endswith('.gz'):
                d = zlib.decompressobj(zlib.MAX_WBITS | 32)
                curl.setopt(pycurl.WRITEFUNCTION, write_gz)
            curl.perform()

        except pycurl.error:
            return False

    if os.path.isfile(dev):
        disk.seek(size - 1)
        disk.write(b"\0")

    return True

解决方案

问题出在LZ4的解压方式:你用的lz4.decompress()是处理原始LZ4块的,而OS镜像采用的是LZ4 frame格式(对应lz4.frame模块的处理逻辑)。流式处理时需要用lz4.frame.Decompressor()来逐块处理数据,而不是直接用lz4.decompress()。

修改后的代码如下:

def write_to_disk(self, url, dev, proxy=None):

    if os.path.isfile(dev):
        size = os.path.getsize(dev)

    with open(os.path.realpath(dev), 'wb') as disk:
        disk.seek(0)

        def write_gz(buf):
            disk.write(d.decompress(buf))

        # 初始化LZ4 frame流式解压器
        lz4_decompressor = lz4.frame.Decompressor()
        def write_lz4(buf):
            # 流式解压当前块并写入磁盘
            disk.write(lz4_decompressor.decompress(buf))

        try:
            curl = pycurl.Curl()
            curl.setopt(pycurl.URL, url)
            if proxy is not False:
                curl.setopt(pycurl.PROXY, proxy)
            curl.setopt(pycurl.BUFFERSIZE, 1024)
            if url.endswith('.lz4'):
                curl.setopt(pycurl.WRITEFUNCTION, write_lz4)
            elif url.endswith('.gz'):
                d = zlib.decompressobj(zlib.MAX_WBITS | 32)
                curl.setopt(pycurl.WRITEFUNCTION, write_gz)
            curl.perform()

            # 处理LZ4解压的剩余数据
            if url.endswith('.lz4'):
                remaining_data = lz4_decompressor.flush()
                if remaining_data:
                    disk.write(remaining_data)

        except pycurl.error:
            return False

    if os.path.isfile(dev):
        disk.seek(size - 1)
        disk.write(b"\0")

    return True

关键修改点

  • 初始化lz4.frame.Decompressor()实例,用于流式处理LZ4 frame数据
  • write_lz4函数用该实例的decompress()方法处理每一块缓存数据
  • 在curl.perform()完成后,调用flush()获取剩余的解压数据并写入磁盘

这样就能实现和io.BytesIO全量处理一致的正确解压效果,同时避免全量缓存的冗余。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 02:53:15