簡體   English   中英

如何使用 pyscript 加載 zip 文件並保存到虛擬文件系統中

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM