[英]How to load a zip file with pyscript and save into the virtual file system
我正在嘗試加載 zip 文件並將其保存在虛擬文件系統中,以便使用 pyscript 進行進一步處理。 在這個例子中,我的目標是打開它並列出它的內容。
據我所知:
請參閱下面的自立 html 代碼,改編自教程(感謝作者,順便說一句)
它能夠加載 Pyscript,讓用戶 select 一個文件並加載它(盡管看起來格式不正確)。 它創建一個虛擬 zip 文件並將其保存到虛擬文件中,並列出內容。 所有這些都是預先工作的,如果我將 process_file function 指向那個虛擬 zip 文件,它確實會打開並列出它。
不工作的部分是當我通過按鈕/文件選擇器 select 在本地文件系統中任何有效的 zip 文件時,將數據加載到data
中時它是文本(utf-8),我收到此錯誤:
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
我嘗試保存到文件並加載它,而不是使用 BytesIO,還嘗試了從這里使用 ArrayBuffer 或 Stream 的變體我還嘗試創建 FileReader 並使用 readAsBinaryString() 或 readAsText() 和各種轉換,結果相同:要么它無法識別“幻數”,要么我得到“不是 zip 文件”。 當喂一些流或 arrayBuffer 時,我會得到以下變化:
TypeError: a bytes-like object is required, not 'pyodide.JsProxy'
在這一點上,我懷疑有一些令人尷尬的明顯但我無法看到,因此,非常感謝任何新的眼睛和關於如何最好/簡單地加載文件的建議:)非常感謝提前。
<!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, FileReader
from pyodide import create_proxy
import io
async def process_file(event):
fileList = event.target.files.to_py()
for f in fileList:
data= await f.text()
mf=io.BytesIO(bytes(data,'utf-8'))
with zipfile.ZipFile(mf,"r") as zf:
nl=zf.namelist()
nlf=" _ ".join(nl)
document.getElementById("content").innerHTML=nlf
def main():
# Create a Python proxy for the callback function
# process_file() is your function to process events from FileReader
file_event = create_proxy(process_file)
# Set the listener to the callback
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: # use `wb` mode
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>
你非常接近你的代碼。 問題在於將文件數據轉換為正確的數據類型。 要求是將arrayBuffer
轉換為Uint8Array
,然后轉換為bytearray
。
導入所需的function:
from js import Uint8Array
將文件data
讀入一個arrayBuffer
並復制到一個新的Uint8Array
data = Uint8Array.new(await f.arrayBuffer())
將Uint8Array
轉換為bytearray
期望的字節數組
mf = io.BytesIO(bytearray(data))
作為參考,根據 John Hanley 的回復(再次感謝),這里是工作代碼:添加在虛擬文件系統中保存為二進制文件並從該文件加載的演示:
<!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>File 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, FileReader, Uint8Array
from pyodide import create_proxy
import io
async def process_file(event):
fileList = event.target.files.to_py()
for f in fileList:
data = Uint8Array.new(await f.arrayBuffer())
mf = io.BytesIO(bytearray(data))
with zipfile.ZipFile(mf,"r") as zf:
nl=zf.namelist()
nlf=" ".join(nl)
document.getElementById("content").innerText+= "\n Test 2: reading file from local file system: "+f.name+" content:"+nlf
with open("b.zip","wb") as outb:
outb.write(bytearray(data))
with zipfile.ZipFile("b.zip", "r") as zf:
nl=zf.namelist()
nlf=" ".join(nl)
document.getElementById("content").innerText += "\n Test 3: reading the same file but first save it in virtual fs and read it: " + nlf
def main():
# Create a Python proxy for the callback function
# process_file() is your function to process events from FileReader
file_event = create_proxy(process_file)
# Set the listener to the callback
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.zip", "wb") as f: # use `wb` mode
f.write(mf.getvalue())
with zipfile.ZipFile("a.zip", "r") as zf:
nl=zf.namelist()
nlf=" ".join(nl)
document.getElementById("content").innerText = "Test 1: reading a dummy zip from virtual file system: " + nlf
main()
</py-script>
</body>
</html>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.