如何使用PyScript加载Zip文件并保存至虚拟文件系统
PyScript加载本地Zip文件失败问题排查与解决
问题背景
尝试用PyScript加载本地Zip文件到虚拟文件系统,目标是打开Zip并列出其中内容。目前已实现:
- 成功加载PyScript,支持文件选择操作
- 能创建虚拟Zip文件并保存到虚拟文件系统,可正常列出其内容
- 虚拟Zip文件能被
process_file函数正确处理
但选择本地有效Zip文件时,始终无法正常解析,触发格式错误。
错误信息
选择本地Zip文件后,出现以下核心错误:
File "/lib/python3.10/zipfile.py", line 1353, in _RealGetContents raise BadZipFile("Bad magic number for central directory") zipfile.BadZipFile: Bad magic number for central directory
尝试用ArrayBuffer/Stream等方式读取时,还会出现类型错误:
TypeError: a bytes-like object is required, not 'pyodide.JsProxy'
问题根源
核心错误在于用文本方式读取二进制Zip文件:原代码中await f.text()将二进制Zip文件按UTF-8文本读取,再通过bytes(data,'utf-8')转回字节流。这个过程会破坏二进制数据(Zip文件包含大量非UTF-8兼容的字节),导致Zip文件的魔术数字(用于识别Zip格式的标识字节)被篡改,无法被zipfile.ZipFile识别。
解决方案
改用二进制方式读取文件:利用File对象的arrayBuffer()方法获取原始二进制数据,再转换为Python的bytes对象,最后用BytesIO包装供zipfile处理。
修改process_file函数如下:
async def process_file(event): fileList = event.target.files.to_py() for f in fileList: # 读取原始二进制ArrayBuffer buffer = await f.arrayBuffer() # 将JS ArrayBuffer转换为Python可识别的bytes对象 data = bytes(buffer) mf = io.BytesIO(data) with zipfile.ZipFile(mf, "r") as zf: nl = zf.namelist() nlf = " _ ".join(nl) document.getElementById("content").innerHTML = nlf
完整修改后的代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" /> <script defer src="https://pyscript.net/alpha/pyscript.js"></script> <title>Example</title> </head> <body> <p>Example</p> <br /> <label for="myfile">Select a file:</label> <input type="file" id="myfile" name="myfile"> <br /> <br /> <div id="print_output"></div> <br /> <p>File Content:</p> <div style="border:2px inset #AAA;cursor:text;height:120px;overflow:auto;width:600px; resize:both"> <div id="content"> </div> </div> <py-script output="print_output"> import asyncio import zipfile from js import document from pyodide import create_proxy import io async def process_file(event): fileList = event.target.files.to_py() for f in fileList: buffer = await f.arrayBuffer() data = bytes(buffer) mf = io.BytesIO(data) with zipfile.ZipFile(mf, "r") as zf: nl = zf.namelist() nlf = " _ ".join(nl) document.getElementById("content").innerHTML = nlf def main(): file_event = create_proxy(process_file) e = document.getElementById("myfile") e.addEventListener("change", file_event, False) mf = io.BytesIO() with zipfile.ZipFile(mf, mode="w",compression=zipfile.ZIP_DEFLATED) as zf: zf.writestr('file1.txt', b"hi") zf.writestr('file2.txt', str.encode("hi")) zf.writestr('file3.txt', str.encode("hi",'utf-8')) with open("a.txt.zip", "wb") as f: f.write(mf.getvalue()) with zipfile.ZipFile("a.txt.zip", "r") as zf: nl=zf.namelist() nlf=" ".join(nl) document.getElementById("content").innerHTML = nlf main() </py-script> </body> </html>
内容的提问来源于stack exchange,提问作者whydoesntwork
相关产品推荐
相关产品推荐

