python加载zip与内存中的模块

时间:2016-08-25 02:22:05

标签: python

所以假设我有一个包含模块/类的zip文件。然后我读了这个文件 - 读取二进制文件(“rb”)将其存储到内存中。我如何将此zip文件放在内存中并从中加载模块。我需要为此编写一个导入钩子吗?一个人不能简单地从内存中运行exec二进制zip数据,可以吗?

我知道从磁盘上的普通zip文件加载模块很简单,因为这是由python2.7自动完成的。然而,我;想知道这是否可以通过记忆。

更新: 很多人都提到从磁盘导入zip。问题是我想从内存NOT磁盘导入zip。我显然会逐字节地将它从磁盘读入内存。我想从构成zip文件的内存中获取所有这些字节,并将其用作常规导入。

2 个答案:

答案 0 :(得分:5)

编辑:修正ZipImporter适用于所有内容(我认为)

测试数据:

mkdir mypkg
vim mypkg/__init__.py
vim mypkg/test_submodule.py

__init__.py内容:

def test():
    print("Test")

test_submodule.py内容:

def test_submodule_func():
    print("This is a function")

创建测试Zip(在Mac上):

zip -r mypkg.zip mypkg
rm -r mypkg # don't want to accidentally load the directory

inmem_zip_importer.py中的特殊拉链导入:

import os
import imp
import zipfile

class ZipImporter(object):
    def __init__(self, zip_file):
        self.z = zip_file
        self.zfile = zipfile.ZipFile(self.z)
        self._paths = [x.filename for x in self.zfile.filelist]

    def _mod_to_paths(self, fullname):
        # get the python module name
        py_filename = fullname.replace(".", os.sep) + ".py"
        # get the filename if it is a package/subpackage
        py_package = fullname.replace(".", os.sep, fullname.count(".") - 1) + "/__init__.py"
        if py_filename in self._paths:
            return py_filename
        elif py_package in self._paths:
            return py_package
        else:
            return None

    def find_module(self, fullname, path):
        if self._mod_to_paths(fullname) is not None:
            return self
        return None

    def load_module(self, fullname):
        filename = self._mod_to_paths(fullname)
        if not filename in self._paths:
            raise ImportError(fullname)
        new_module = imp.new_module(fullname)
        exec self.zfile.open(filename, 'r').read() in new_module.__dict__
        new_module.__file__ = filename
        new_module.__loader__ = self
        if filename.endswith("__init__.py"):
            new_module.__path__ = [] 
            new_module.__package__ = fullname
        else:
            new_module.__package__ = fullname.rpartition('.')[0]
        return new_module

使用:

In [1]: from inmem_zip_importer import ZipImporter
In [2]: sys.meta_path.append(ZipImporter(open("mypkg.zip", "rb")))
In [3]: from mypkg import test
In [4]: test()
Test function
In [5]: from mypkg.test_submodule import test_submodule_func
In [6]: test_submodule_func()
This is a function

(来自efel)还有一件事......:

要直接从内存中读取,需要执行此操作:

f = open("mypkg.zip", "rb")

# read binary data we are now in memory
data = f.read()

f.close()  #important! close the file! we are now in memory

# at this point we can essentially delete the actual on disk zip file

# convert in memory bytes to file like object
zipbytes = io.BytesIO(data)

zipfile.ZipFile(zipbytes)

答案 1 :(得分:-2)

从zip读取test.txt(不解压缩或写入磁盘):

python 3(如果使用py2.x,则应将py3 zip API更改为py2)

import zipfile

file_rst = []
with zipfile.ZipFile('/test/xxx.zip') as my_zip:
    with my_zip.open('test.txt') as my_file:
        for line in my_file:
            file_rst.append(line.strip())