Затем, мы выгружаем наш файл изображения, вызывая метод storbinary(). Этот метод принимает имя целевого файла с префиксом STOR, как первый аргумент, и открытый файловый дескриптор как второй аргумент. Мы предоставляем последний, вызывая встроенную функцию Питона open() с именем нашего файла изображения в качестве единственного аргумента. (Если нужна дополнительная информация о довольно диковинном поведении модуля ftplib, ссылка на его документацию: http://docs.python.org/library/ftplib.html.) Мы грациозно заканчиваем связь в FTP-сервером, вызывая метод quit(), и сообщаем пользователю о завершении задачи, показывая сообщение с упоминанием имени целевого файла, так как оно может отличаться от ожидаемого, если существует файл с аналогичным именем:
ftp.storbinary('STOR '+dstfilename,open(filename))
ftp.quit()
Draw.PupMenu('Render result stored as "%s"%s|Ok'
%(dstfilename,'%t'))
Полный код доступен как ftp.py в файле ftp.blend. Его можно запустить из текстового редактора, но в общем случае, несомненно, значительно удобнее поместить ftp.py в каталог скриптов Блендера. Скрипт сконфигурирован так, чтобы он был доступен в меню Файл | Экспорт (File | Export).
Весенняя уборка - архивация неиспользуемых изображений
Через некоторое время у любого долгоживущего проекта набирается много хлама. Например, изображения текстур, которые Вы пытались применить, но они были отвергнуты в пользу более подходящих. Этот скрипт поможет нам найти все файлы в выбранном каталоге, на которые нет ссылок в нашем .blend файле, и упаковать их в ZIP-архив.
Мы позаботимся о том, чтобы не переносить никаких .blend файлов в ZIP-архив (в конце концов, мы, как правило, хотим быть в состоянии рендерить), ни самого ZIP-архива (для предотвращения бесконечной рекурсии). Любой файл, который мы архивируем, мы затем попытаемся удалить, и если удаление файла оставляет пустой каталог, мы удалим также этот каталог, если он не является тем каталогом, где находится наш .blend файл.
Функции работы с файлами предоставляются модулями Питона os и os.path, а ZIP-файлами, которые могут использоваться как в Windows так и на открытых платформах, можно манипулировать с помощью модуля zipfile. ZIP-файл, в который мы перемещаем неиспользованные файлы, мы назовём Attic.zip:
import Blender
from os import walk,remove,rmdir,removedirs
import os.path
from zipfile import ZipFile
zipname = 'Attic.zip'
Первой задачей будет сгенерировать список всех файлов в каталоге, где находится наш .blend-файл. Функция listfiles() использует функцию walk() из модуля Питона os, чтобы рекурсивно обойти дерево каталогов и построить список файлов при обходе.
По умолчанию, функция walk() проходит по дереву каталогов первой глубины, что позволяет нам изменять список каталогов на лету. Эта возможность используется здесь, чтобы удалить любые каталоги, которые начинаются с точки (выделено). Это не необходимо для текущего и родительского каталогов (они представлены посредством .. и . соответственно), поскольку walk() уже фильтрует их, но это позволяет нам, например, также отфильтровать любые .svn каталоги, которые могут нам встретиться.
Строка, содержащая оператор yield, возвращает как результат один файл за один раз, так что наша функция может быть использована как итератор. (Для дополнительной информации об итераторах, смотрите online-документацию по адресу http://docs.python.org/reference/simple_stmts.html#yield) Мы соединяем соответствующее имя файла и путь, чтобы сформировать полное имя, и нормализуем его (то есть, удаляем двойные разделители пути и тому подобное); хотя нормализация здесь не строго необходима, поскольку walk() должна возвращать любые пути в нормализованной форме:
def listfiles(dir):
for root,dirs,files in walk(dir):
for file in files:
if not file.startswith('.'):
yield os.path.normpath(
os.path.join(root, file))
for d in dirs:
if d.startswith('.'):
dirs.remove(d)
Прежде, чем мы сможем сравнить список файлов, которые используются нашим .blend-файлом со списком файлов, присутствующих в каталоге, мы убеждаемся, что любой упакованный файл распакован на свое первоначальное местоположение. Не строго необходимо, но позволяет удостовериться, что мы не перемещаем в архив никаких файлов, которые непосредственно не используются, но имеют копию в .blend-файле:
def run():