Python: могут ли исполняемые файлы zip включать файлы данных?

Являясь довольно новым для python, я только недавно обнаружил возможность непосредственного выполнения .zip файла, поместив __main__.py файл в начало файла. Это отлично работает для кода python, но могу ли я объединить другие типы файлов и получить доступ к ним с помощью моих скриптов? Если да, то как?

Моя конечная цель состояла бы в том, чтобы связать некоторые файлы изображений вместе с кодом python в одном .zip файле, а затем иметь возможность использовать эти изображения в приложении без необходимости извлекать их на диск. Я также хотел бы связать уведомление об авторских правах, заметки о выпуске и т.д., Чтобы все приложение и его файлы данных находились в одном zip файле, который может быть выполнен без необходимости его извлечения.

Ответы

Ответ 1

Вы можете использовать pkg_resources функции для доступа к файлам:

# __main__.py
import pkg_resources
from PIL import Image

print pkg_resources.resource_string(__name__, 'README.txt')

im = Image.open(pkg_resources.resource_stream('app', 'im.png'))
im.rotate(45).show()

Где zipfile содержит:

.
|-- app
|   |-- im.png
|   `-- __init__.py
|-- README.txt
`-- __main__.py

Чтобы сделать исполняемый файл zipfile, запустите:

$ echo '#!/usr/bin/env python' | cat - zipfile > program-name
$ chmod +x program-name

Чтобы проверить это:

$ cp program-name /another-dir/
$ cd /another-dir && ./program-name

Ответ 2

По крайней мере, на моем Linux-сервере нет открытого дескриптора файла или сопоставленной памяти процессом в свой собственный zip файл, поэтому, по-видимому, нет возможности "магически" получить к нему доступ.

Однако создание вашего собственного доступа не так уж сложно. Создайте __main__.py так:

import os, zipfile

me = zipfile.ZipFile(os.path.dirname(__file__), 'r')
f = me.open('other.txt')
print f.read()
f.close()
me.close()

Изменить: немного кратким. Для полноты:

$ echo "Hello ZIP" > other.txt
$ zip testo.zip __main__.py other.txt
$ python testo.zip
Hello ZIP

Ответ 4

pkgutil.get_data(package, resource) берет имя пакета и ресурса. Это означает, что вы должны поместить свои файлы данных внутри пакета в zip файл.

Так, например, zip файл, содержащий:

__main__.py
zippeddata/__init__.py
zippeddata/data.txt

Файл __init__.py может быть пустым или просто комментарием, но вам нужно сделать zippeddata импортируемый.

Затем в __main__.py вы просто вызываете:

data = pkgutil.get_data('zippeddata', 'data.txt')