В конце своей работы сценарий putfile.py сохраняет выгруженный файл на сервер в жестко определенном каталоге uploaddir под тем именем, которое задано в конце пути к файлу на стороне клиента (то есть без пути каталога на стороне клиента). Обратите, однако, внимание, что функции splitpath в этом сценарии приходится делать дополнительную работу для извлечения базового имени файла в правой части. Броузеры могут посылать имя файла в том формате пути каталога, который используется на компьютере клиента. Этот формат пути может не совпадать с тем, который используется на сервере, где выполняется сценарий CGI. Разные броузеры могут действовать по-разному, но об этой проблеме следует помнить, чтобы обеспечить переносимость.
Стандартный инструмент разделения путей на составные части, функция os.path.split, умеет извлекать базовое имя файла, но распознает только символы-разделители пути, которые используются на платформе, где она выполняется. Это означает, что если выполнить этот сценарий CGI в системе Unix, функция os.path.split отрубит путь к каталогу от базового имени по разделителю /. Однако если пользователь выгружает файл из DOS или Windows, то разделителем в переданном имени файла будет \, а не /. Броузеры, работающие в некоторых версиях Macintosh, могут отправлять еще более отличающиеся пути.
Чтобы обеспечить универсальную обработку путей в формате клиентов, этот сценарий импортирует из библиотеки Python специфические для платформ модули обработки путей для каждого клиента, который должен поддерживаться, и пытается отделить путь поочередно с помощью каждого из них, пока не будет обнаружено имя файла в правой части. Например, posixpath обрабатывает пути, используемые в системах Unix, а ntpath распознает пути клиентов DOS и Windows. Обычно мы не импортируем эти модули напрямую, поскольку os.path.split автоматически загружает тот из них, который соответствует платформе, где действует сервер; однако в данном случае нам необходимо использовать специализированные версии, поскольку путь поступает с другого компьютера. Обратите внимание, что можно было бы запрограммировать логику разделения пути иным образом, чтобы избежать нескольких вызовов split:
def splitpath(origpath): # получить имя в конце
basename = os.path.split(origpath)[1] # формат платформы сервера if basename == origpath: # без изменений?
if ‘\\’ in origpath:
basename = origpath.split(‘\\’)[-1] # формат DOS
elif ‘/’ in origpath:
basename = origpath.split(‘/’)[-1] # формат Unix return basename
Но эта альтернативная версия может терпеть неудачу для некоторых форматов путей (например, для пути DOS с именем диска, но без символов обратного слэша). В настоящем виде в обоих вариантах попусту тратится время, если имя файла уже является базовым (то есть не содержит слева пути к каталогу), но в целом мы должны учитывать более сложные случаи.
Этот сценарий выгрузки файлов на сервер работает так, как задумано, но следует сделать некоторые замечания, прежде чем перевернуть страницу после этого примера:
• Во-первых, сценарий putfile никак не учитывает несовместимости, существующие между разными платформами в самих именах файлов. Например, пробелы в имени файла, передаваемом клиентом DOS, не преобразуются в другие символы — они остаются пробелами в имени файла на стороне сервера, что может быть допустимо, но в некоторых ситуациях затрудняет обработку.
• Во-вторых, предусмотренная процедура построчного чтения означает, что этот сценарий ориентирован на выгрузку текстовых файлов. Он использует режим wb, чтобы сохранить содержимое выгруженного файла в двоичном режиме, но в других местах предполагается, что данные являются текстом, включая создание страницы ответа. Подробнее о двоичных файлах рассказывается в главе 4. Это самый спорный пункт в Python 3.1, так как выгрузка двоичных файлов вообще не поддерживается (смотрите врезку «Ограничения на выгрузку файлов модели CGI в версии 3.1»). Однако в будущих версиях эта проблема, возможно, будет решена.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, II том, 2011