DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
搬瓦工;先看线路,再选 VPS;CN2 GIA · 对应线路套餐;查看线路 →
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS

fsspec ZIP close 后目标仍不存在,检查 simplecache 外层提交

fsspec 2026.9.0 的 ZIP close 只结束归档层,simplecache 外层文件可能仍未提交。显式管理外层上下文,先完成 ZIP,再关闭并从目标重新读取校验。

通过 simplecache:: 写入 ZIP,调用 ZipFileSystem.close() 没报错,目标路径却仍不存在;删除对象、等垃圾回收后,文件反而出现。这可能是归档与外层缓存文件只关闭了一层。

fsspec 2026.9.0 的正式 ZipFileSystem.close() 只关闭内部 zipfile.ZipFile。若外层文件由 ZIP 文件系统自己打开,退出它的上下文则留在析构路径。simplecache 写入文件要在关闭时提交目标,因而持有已经关闭的 ZIP 文件系统对象,仍可能拖住这一步。

由应用显式管理外层文件

应用可以先打开外层写入上下文,再让 ZIP 写入器使用这个文件对象,并保证先写完 ZIP 尾部,再退出外层上下文。以下示例使用独立的内存目标,不会写云端对象;cache_dir 应传入应用自有、可清理的缓存目录:

import io
import uuid
import zipfile
import fsspec


def make_archive(cache_dir: str) -> bytes:
    name = f"archive-{uuid.uuid4().hex}.zip"
    with fsspec.open(
        f"simplecache::memory://{name}",
        "wb",
        simplecache={"cache_storage": cache_dir},
    ) as outer:
        with zipfile.ZipFile(outer, mode="w") as archive:
            archive.writestr("data.jsonl", b'{"text":"example"}\n')

    memory = fsspec.filesystem("memory")
    payload = memory.cat_file(name)
    with zipfile.ZipFile(io.BytesIO(payload), "r") as archive:
        assert archive.read("data.jsonl") == b'{"text":"example"}\n'
    return payload

这里用标准库 ZIP 写入器建立清楚的所有权:它关闭时先完成 ZIP 目录,外层 fsspec.open 随后关闭缓存文件并提交目标。若业务需要 ZipFileSystem 的其他接口,也应保持相同的关闭顺序,并确认文件对象究竟由谁负责关闭。

不要先关闭外层文件再让 ZIP 写入器写目录;那会把提交时机问题变成不完整归档或已关闭文件错误。也不要把 del fs; gc.collect() 当成提交协议,引用关系和垃圾回收时机都不是可靠的业务边界。

close 成功后,仍要核对真正的目标

检查目标文件存在,并从目标后端重新读取归档,核对成员名和内容;只在本地 simplecache 路径找到文件,不能证明上传已经发生。远程对象存储的权限、网络失败和重试策略仍可能让提交失败,内存示例不覆盖这些条件。

写入业务目标时,应使用独立的新对象名,验证完成后再按后端支持的方式切换引用,避免为了重试覆盖唯一的有效副本。保留外层关闭阶段抛出的异常,不能只看 ZIP 内层关闭是否成功。

升级 fsspec 后,也应在对象仍被持有的条件下检查目标可读,而不是等待析构恰好替应用完成关闭。