Этот сценарий может выполняться в Windows и Unix-подобных системах, поэтому текстовые файлы должны обрабатываться особым способом. Как и при загрузке каталога с сервера, этот сценарий выбирает текстовый или двоичный режим передачи, определяя тип файла с помощью модуля mimetypes по его расширению в имени — файлы HTML и текстовые файлы перемещаются в текстовом режиме FTP. Мы уже знакомы с методом storbinary объекта FTP, применяемым для выгрузки файлов в двоичном режиме, — на удаленном сайте оказывается точная, байт в байт, копия файла.
Передача в текстовом режиме действует почти так же: метод stor- lines принимает строку команды FTP и объект локального файла (или похожего на файл) и просто копирует каждую строку локального файла в одноименный файл на удаленном компьютере.
Однако обратите внимание, что в Python 3.X локальный текстовый файл должен открываться в двоичном режиме rb. Входные текстовые файлы обычно открываются в текстовом режиме r, что обеспечивает декодирование в символы Юникода и преобразование в Windows любых последовательностей \r\n конца строки в платформонезависимые символы \n в процессе чтения строк. Однако модуль ftplib в Python 3.1 требует, чтобы текстовые файлы открывались в двоичном режиме rb, потому что он сам преобразует все символы конца строки в последовательности \r\n при передаче, а для этого он должен читать строки как простые последовательности байтов с помощью readlines и выполнять обработку строк bytes, которые возвращаются в двоичном режиме.
Модуль ftplib мог работать в Python 2.X со строками, читаемыми из файлов в текстовом режиме, но лишь по той простой причине, что в этой версии отсутствовал отдельный тип bytes — символы \n просто замещались последовательностями \r\n. Открытие локального файла в двоичном режиме также означает, что при чтении его модулем ftplib не будет выполняться декодирование в символы Юникода: текст передается через сокеты как строка байтов в кодированной форме. Все это, конечно, является наглядным примером влияния особенностей кодирования Юникода — за подробностями обращайтесь к файлу модуля ftplib.py в каталоге с исходными текстами библиотеки Python.
В двоичном режиме передачи все обстоит еще проще — двоичные файлы открываются в режиме rb, чтобы подавить декодирование в символы Юникода и другие автоматические преобразования, и возвращают строки bytes, ожидаемые модулем ftplib при чтении. Двоичные данные не являются текстом Юникода, и нам не нужно, чтобы байты в аудиофайле, значение которых случайно совпадает с \r, таинственным образом исчезали при чтении в Windows.
Как и в сценарии загрузки каталога с сервера, эта программа обходит все файлы, которые должны быть переданы (в данном случае в локальном каталоге), и поочередно передает их — в текстовом или двоичном режиме в зависимости от имени файла. Ниже приводится команда, которой я пользуюсь для выгрузки целиком моего сайта с моего ноутбука с Windows на удаленный Linux-сервер моего интернет-провайдера за один шаг:
C:\…\PP4E\Internet\Ftp\Mirror> uploadflat.py test
Password for lutz on learning-python.com:
Clean remote directory first? y connecting…
deleting remote . cannot delete remote . deleting remote .. cannot delete remote ..
deleting remote 2004-longmont-classes.html
deleting remote 2005-longmont-classes.html
deleting remote 2006-longmont-classes.html
deleting remote about-lp1e.html
deleting remote about-lp2e.html
deleting remote about-lp3e.html
deleting remote about-lp4e.html
…часть строк опущена…
uploading test\2004-longmont-classes.html to 2004-longmont-classes.html as text
uploading test\2005-longmont-classes.html to 2005-longmont-classes.html as text
uploading test\2006-longmont-classes.html to 2006-longmont-classes.html as text
uploading test\about-lp1e.html to about-lp1e.html as text
uploading test\about-lp2e.html to about-lp2e.html as text
uploading test\about-lp3e.html to about-lp3e.html as text
uploading test\about-lp4e.html to about-lp4e.html as text
uploading test\about-pp-japan.html to about-pp-japan.html as text
…часть строк опущена…
uploading test\whatsnew.html to whatsnew.html as text
uploading test\whatsold.html to whatsold.html as text
uploading test\wxPython.doc.tgz to wxPython.doc.tgz as application gzip
uploading test\xlate-lp.html to xlate-lp.html as text
uploading test\zaurus0.jpg to zaurus0.jpg as image
uploading test\zaurus1.jpg to zaurus1.jpg as image
uploading test\zaurus2.jpg to zaurus2.jpg as image
uploading test\zoo-jan-03.jpg to zoo-jan-03.jpg as image
uploading test\zopeoutline.htm to zopeoutline.htm as text
Done: 297 files uploaded.
Для моего сайта на моем текущем ноутбуке с беспроводным подключением весь процесс обычно занимает около шести минут, в зависимости от загруженности сервера. Как и в примере с загрузкой каталога, я часто выполняю эту команду из локального каталога, где хранятся мои вебфайлы, и передаю интерпретатору Python полный путь к сценарию. Когда я запускаю этот сценарий на Linux-сервере, он действует так же, но я указываю иные пути к сценарию и к каталогу с моими веб-файлами.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, II том, 2011