Саммерфилд - Программирование на Python 3 (1077331), страница 76
Текст из файла (страница 76)
тпт1 (). Ключами словаря являются идентификаторы отчетов, а значениями — объекты 1пстзепт. Мы переопределили методы уа1вев( ), 11евв( ) и Кеув() так, чтобы возвращаемые ими итераторы обеспечивали выполнение итераций в порядке сортировки идентификаторов отчетов. Такое поведение обусловлено тем, что методы уа1пев() и11еэв() используют итератор по ключам, возвращаемый методом 1пстсеп1Сс11есттоп. Кеув(), а этот метод (который имеет еще одно имя: 1пс1Зеп1Со1!ес1[оп, 11ег ()) выполняет в порядке сортировки итерации по ключам, возвращаемым методом с[с1. Кеув() базового класса. Дополнительно класс 1пс1эептСо!1ес1[оп имеет методы ехрогт() и [врогт (). (Мы использовали завершающий символ подчеркивания, чтобы обеспечить отличие имени метода от встроенной инструкции [эрог1.) Методу ехрог1() передается имя файла и в виде необязательных аргументов — средство записи и флаг сжатия, а он на основе имени файла и средства записи передает управление более конкретному методу, такому как ехрог1 хв1 Сов() или ехрогт хз1 е1гее().
Метод 1врогт () принимает имя файла и средство чтения в виде необязательного аргумента и работает похожим образом. Методам импортирования, работающим с двоичными форматами, не передается информация о том, был ли сжат файл — как ожидается, они сами будут определять это и работать соответственно. Запись и чтение двоичных данных Двоичные форматы даже без сжатия обычно являются более компактными и, как правило„обеспечивают более высокую скорость сохране- з41 Запись и чтение двоичных данных ния и загрузки. Наиболее простой способ заключается в использовании модуля ртсК1е, хотя при обработке двоичных данных вручную обычно получаются файлы меньшего размера. Консервирование с возможным сжатием Консервирование является наиболее простым подходом к вы- ун, полнению операций сохранения и загрузки данных в программах на языке Ру()топ, но, как уже отмечалось в предыдущей главе, процедура консервирования не имеет механизмов обеспечения безопасности (шифрование, цифровая подпись), поэтому загрузка законсервированных объектов из непроверенных источников может оказаться опасной.
Проблема безопасности обусловлена тем, что законсервированные объекты могут импортировать произвольные модули и вызывать произвольные функции, то есть можно создать такой законсервированный объект, который, к примеру, после загрузки будет заставлять интерпретатор выполнять неблаговидные действия. Тем не менее консервирование часто является идеальным средством для работы с узкоспециализированными данными, особенно в программах, предназначенных для личного пользования. Обычно намного проще сначала выработать формат файла и написать программный код, выполняющий сохранение, а потом написать программный код, выполняющий загрузку, поэтому мы начнем с того, что рассмотрим реализацию консервирования коллекции записей об инцидентах.
Оет ехрогт р!сК1е(ае!Г, Г!1епаве, совргеаа=ра1ее): гп = иове тгу; тт совргеаа: ГП = Ох!р.осев(Г!1епаве, твЬ") е1ее: Гп = преп(тт1епаве, тзЬ") ртсК1е.совр(ае1(, ТЬ, р!ЬК1е.н1ОНЕЗТ РВОТОСОК) ге!иго Тгое ехсерт (Епн!гопвеп(Еггог, ртсК1е.РтсК1тпОЕггог) аа егг: ргтпт("(0): ехрог! еггог: ( 1)".
гогват( оа,рать.ьаеепаве(ауа.агру[0]), егг)) гетега Ра1ае Т!па1!у: тт Гп !а пот Иове; Гв,с1оае() Если было запрошено сжатие, для открытия файла используется функция Ог!р. ореп() из модуля Оатр, в противном случае используется встроенная функция ореп(). При консервировании данных в двоичном формате мы должны использовать двоичный режим записи (тиЬ"). 342 Глава 7. Работа с файлами (В Ру1)топ 3.0 константа р1сК1е. Н16НЕЯТ РНОТОСО1 обозначает протокол 3, соответствующий компактному двоичному формату.') о В случае появления ошибок мы предпочитаем сразу же щмзкстз сообщать о них пользователю и возвращать вызываюСтэ.423 ЩЕй ПРОГРаММЕ ЛОГИЧЕСКОЕ ЗНаЧЕНИЕ, СВИДЕтЕЛЬСтВУЮ- щее об успехе или неудаче.
В методе используется блок Гт пз11у, чтобы обеспечить закрытие файла независимо от наличия ошибки. В главе 8 будет представлен более компактный способ закрытия файлов, в котором не используется блок (1ла11у. Этот программный код очень напоминает то, что мы уже видели в предыдущей главе, но здесь есть один тонкий момент, о котором необходимо упомянуть. Консервированию подвергается объект ве11 класса бтст. Но значениями словаря являются объекты класса 1лс1белт, то есть объекты нашего собственного класса. Модуль ртсК1е достаточно интеллектуален, чтобы сохранять объекты почти любых наших классов без нашего вмешательства. Вообще, консервироваться могут логические значения, числа и строки, а также экземпляры классов, включая нестандартные классы, предоставляющие частный атрибут б1ст .
Кроме того, консервироваться могут любые встроенные типы коллекций (кортежи, списки, множества, словари), если они содержат только объекты, допускающие возможность консервирования (включая коллекции, то есть поддерживаются рекурсивные структуры). Имеется также возможность консервировать другие типы объектов или экземпляры нестандартных классов, которые обычно не могут консервироваться (например, потому что они имеют атрибуты, не допускающие возможность консервирования), для чего достаточно или оказать некоторую помощь модулю р)сК1е, или реализовать функции сохранения и загрузки.
Все необходимые подробности вы найдете в электронной документации к модулю ртсК1е. Чтобы прочитать законсервированные данные, необходимо определить — были ли они сжаты или нет. Любой файл, сжатый с использованием алгоритма из1р, начинается с сигнатуры файла (так(с питбег). Сигнатура — это последовательность из одного или более байтов в начале файла, используемая для обозначения типа файла. Для обозначения файлов, сжатых с использованием алгоритма бз1р, используется Протокол 3 впервые появился только в Рутйоп 3.
Если необходимо создавать файлы, доступные для чтения и записи программам, работающим под управлением Рут)топ 2 и РутЬоп 3, необходимо использовать протокол 2. Запись и чтение двоичных данных 343 снгнатура нз двух байтов Ох1Р Ох88, которые мы сохраняем в перемен- ной типа Ьутеа: 611Р МА61С = Ь"1х1Р1хВВ" Подробнее о типе данных Ьу!еа рассказывается во врезке «Тяпы данных ЬуСеа н ЬуСеаггау» (стр. 344), а в табл.
7.3 (стр. 345-347) перечнсляются нх методы. Ниже приводится программный код, выполняющий чтение законсер- внрованных данных: Оет 1врогт р1ох1е(ае1(, (11епаве): ЕП = попе тгу: (П = преп(тт1епаве, "гЬ") вадтс = Го.геае(1еп(611Р МА61С)) !т вац(с == 61!Р МА61С; Го.о1оае() ГП = цхтр.преп(Г11епаве, "гЬ") е1ае: гп.аеек(0) ае1т.о1еаг() ае1(,ороате(рток1е. 1оао((ь)) гетега тгое ехсерт (еп»тгопвептеггог, рток1е.цпр1ок!1пцеггог) аа егг: рг!пт("(О): 1врогт еггог: (1)".(ответ( оа.рать.ьааепаве(ауа.агцч(0)), егг)) гетогп Ра1ае ттпа11у: 11 гп 1а пот папе: то.с1оае() Мы не знаем заранее, был файл сжат нлн нет.
В любом случае, мы начинаем с того, что открываем файл для чтения в двоичном режиме, а затем читаем первые два байта. Если этн два байта представляют снгнатуру йз!р, файл закрывается н создается новый объект файла вызовом функции Оетр, ореп(). Если файл не был сжат, используется объект файла, созданный функцией ореп(); вызовом его метода аееК() указатель позиции в файле перемещается в начало, чтобы следующая операция чтения (выполняемая внутри функции р!СК1е.1оао()) начала чтение файла с самого начала, Мы не можем выполнить прямое прнсванванне объекту ае1(, так как это приведет к уничтожению используемого объекта типа 1пстоепт601- 1ест!оп, поэтому сначала мы удаляем все элементы словаря н затем с помощью метода 0!с!.орцате() заполняем словарь объектами с ннформацией об инцидентах нз словаря типа 10016ептС011ест(оп, загруженного нз файла. Обратите внимание, что порядок следования байтов в машинном слове для данной аппаратной архитектуры не имеет никакого значения, по- Глава 7.
Работа с файлами 344 Типы данных Ьу1е5 и Ьу1еаггау В языке Ру1]топ имеется два типа данных, которые используются для работы с обычными байтами: тип Ьутев — неизменяемый и тип Ьутеа г гау — изменяемый. Оба типа хранят последовательности из нуля или более 3-битовых беззнаковых целых чисел (байтов), где каждый байт может представлять число в диапазоне 0...255. Оба типа очень похожи на строки и предоставляют практически те же методы, включая поддержку срезов.
Кроме того, тип данных Ьу1еаггау предоставляет несколько методов, напоминающих методы класса 1131, позволяющих производить изменения внутри объекта Ьутеа г гау. Все методы этих двух типов данных перечислены в табл. 7. 3 (стр. 345 — 347). Несмотря на то, что операция извлечения среза для объектов Ьутев и Ьутеаггау возвращает объект того же самого типа, тем не менее оператор доступа к элементу ([]) возвращает объект типа тп1 — значение заданного байта. Например: о Метод втг. тгвпв1ате(), отр. 99 иогб = Ьтдп[аа1" х = Ь-Д- ного[0] == х ипгб[; 1] == х ного[0] == х[0] В вернет; Ра1ве В ного[0] == 65; х == Ь"А" Ф вернет.
Тгое В иогб(:1] == Ь"А"; х == Ь"Я" Ф вернет: тгое в ного[0] == 65; х(0] == 65 Ниже приводятся еще несколько примеров использования объ- ектов типа Ьу1еа и Ьутеаггау: бата = Ь"5 Нт11в 1х351х201х481хб9хх601х601х73" бата оррег() В вЕрнЕт: Ь'5 Н11[ 6 5 Н![18' бата.гер1асе(Ь"111", Ь"а1") а вернет: Ь'5 Ната 5 Наев' ьутев.ггоиьех("35 20 48 69 бс бс 73") в вернет: ь'5 н1116' ьутев.ггоапех("352048696сбс73") в вернет: ь'5 нт11в' бата = ьутеаггау(бата) и теперь бата имеет тип ьутеаггау бата.рор(10) В вернет; 72 (огб("Н")) бата. 1пвегт( 10, огб( "В" ) ) 4 бата == Ь'5 НТ11в 5 8411в' Методы, имеющие смысл только применительно к строкам, такие как Ьутев, оррег(), предполагают, что байты соответствуют символам из набора АБО[1.
Метод класса Ьутеа, Тгоалех() игнорирует пробелы и интерпретирует каждую подстроку из двух цифр как шестнадцатеричное число, то есть строка "35" будет преобразована в байт со значением Ох35, и т. д. тому что при чтении сигнатуры мы читаем два отдельных байта, а ко- гда модуль р1сН1е читает основные данные, он сам заботится о порядке следования байтов. Запись и чтение двоичных данных Таблица 7.3. Методы объектов тило Ьу1ез и Ьутеаггау Описание Синтаксис Добавляет целое число ! (в диапазоне 0...