Что такое код zip_entry_close

Содержание

Zip архив в java — компрессия и извлечение файлов

Думаю, многие встречались с необходимостью создавать zip-архивы в java программах. Распаковка архивов из программного кода встречается куда реже, но все же встречается.

Давайте рассмотрим API для работы с архивами. Необходимые нам классы находятся в пакете java.util.zip.

Создание архива

Чтобы создать новый архив необходимо воспользоваться классом ZipOutputStream. Вот список методов, которые могут понадобиться:

  • setLevel — установка уровня компрессии от 0 до 9, где 9 — максимальная компрессия;
  • putNextEntry — вызывается перед записью нового объекта в архив, с указанием имени объекта;
  • closeEntry — вызываем после записи объекта. putNextEntry автоматически вызывает метод closeEntry.
  • close — закрываем поток.

Небольшой пример — создадим архив с названием archive.zip, в котором будут находиться сжатые файлы из директории folder. В этом примере пустые директории будут игнорироваться. Уровень компрессии явно не задан, поєтому будет использоваться значение по-умолчанию.

Обратите внимание, что при создании ZipEntry мы использовали относительный путь, а не просто имя файла. Это сделано для того, чтобы при архивации сохранились все дерево директорий, ведущих к файлу. В случае использования f.getName() в архиве просто будет плоский список файлов без информации о директориях.

Извлечение файлов из архива

Давайте теперь напишем небольшую утилиту на Java для извлечения фалов из zip-архива. Необходимые нам классы из пакета java.util.zip — это ZipFile и ZipEntry.

Для начала проверим, что на вход программы пользователь подал путь к архиву. Далее убедимся, что файл архива существует и может быть прочитан. Если все нормально, переходим непосредственно к процессу разархивации.

ZipFile как понятно из названия класса представляет собой файл архива. Одним из самых важных методов класса есть метод entries(). Метод возвращает перечисление объектов архива.

Итерируя по перечислению мы создаем необходимые пустые директории, если такие имеются, а так же пишем объекты на файловую систему, опять же с сохранением всех директорий.

У объекта ZipEntry кроме getName есть еще такие употребимые методы:

  • getSize — размер файла в несжатом виде;
  • getCompressedSize — размер, занимаемый файлом в архиве;
  • getTime — время последней модификации объекта.

Ну а вот и исходник утилиты:

write() — вспомогательный метод, который пишет из одного потока в другой. Кстати, новичкам стоит запомнить, как из InputStream переписать информацию в OutputStream — такой вопрос периодически задают джуниорам на собеседовании.

Если еще остались вопросы — задавайте их в комментариях, постараюсь помочь.

zip — PHP zip_entry_read Не удалось показать изображение

У меня есть zip-файл «test.zip», который содержит много файлов и изображение под названием «dp.bmp». Поэтому я использую приведенный ниже скрипт для поиска и показа этого файла изображения. Но, к сожалению, изображение не может отображаться правильно.

На изображении показана только горизонтальная линия изображения (не отображается целое изображение по высоте и ширине), как показано ниже:

Затем я попытался изменить строку:

Но все еще показывают только горизонтальную линию этой картинки

Вот мой оригинальный исходный код:

Я также тестировал с другим файлом изображения и форматом, таким как JPG, но все еще не мог показать всю картинку.

Любое решение будет оценено. Спасибо!

Решение

Согласно руководству по PHP, zip_open: некоторые старые версии PHP возвращали false, если zip_open не удался, а более новые версии возвращают число ошибок (в виде целого числа), поэтому вместо этого:

ZipOutputStream — closeEntry() first or close() first

Following is part of the some code. I need to close out resources in finally clause. Do I need to call closeEntry() first or close()? I am getting some error messages.

2 Answers 2

Consider the scheme of using zipout :

So, it the block, where we do something with zipout you should create and close entries:

The resulting scheme is:

So, you should firstly close entry, then zipout .

ZipOutputStream#closeEntry() closes the current entry in the zip file, and because you only have one entry it isn’y that big of a deal. If you need to put another entry in you just have to close the current entry first before putting the next one in.

ZipOutputStream#close() closes the file stream completely, use this when you are done adding stuff to your stream.

TL;DR Put the closeEntry() first if you use it, I don’t know if its even necessary to close the last entry in this type of OutputStream .

Not the answer you’re looking for? Browse other questions tagged java zipoutputstream or ask your own question.

Linked

Hot Network Questions

Subscribe to RSS

To subscribe to this RSS feed, copy and paste this URL into your RSS reader.

site design / logo © 2020 Stack Exchange Inc; user contributions licensed under cc by-sa 4.0 with attribution required. rev 2020.11.12.35412

Что такое зип код (zip postal code)?

Поскольку наш посвящен компьютерам и интернету, мы затрагиваем самые различные темы на нашем сайте. Сегодня разберем не совсем обычный вопрос. Пользователи спрашивают, что такое zip code при регистрации на сайте? Что нужно указывать в этом случае?

Действительно, при регистрации на некоторых сайтах, особенно если речь идет о зарубежных интернет-магазинах, часто требуется указывать zip code. Вот один из примеров, когда имеется поле ZIP/Postal Code.

Другой вариант, когда требуется ввести zip code.

На самом деле все просто: zip code означает почтовый индекс. Если вы покупаете что-нибудь на заграничном сайте, вам обязательно нужно указывать свой почтовый индекс. Конечно, посылка можете дойти и без него (теоретически), но рисковать не стоит, поэтому если данное поле имеется при заполнении данных, не игнорируйте его.

А где же можно узнать свой почтовый индекс, не на почту же идти? Достаточно открыть поисковую систему. Например, в Яндексе напишите индекс по адресу и нажмите кнопку поиска.

Далее под строкой поиска вы увидите строку для ввода адреса. Введите свой адрес, затем нажмите «Узнать».

Индекс перед вами.

Уважаемые пользователи! Если наш сайт вам помог или что-то в нем не понравилось, будем рады, если вы оставите комментарий. Заранее большое спасибо.

Работа с архивами Zip и 7z

В мобильной разработке бывает потребность сделать приложение для работы без интернета. Например, словарь или справочник, который будет использоваться в суровых полевых условиях. Тогда для работы приложения нужно единожды выкачать архив с данными и сохранить его у себя. Сделать это можно посредством запроса в сеть, но так же можно зашить архив с данными внутрь приложения.

Согласно требованиям Google Play, apk-файл приложения должен быть не более 50 МБ, так же можно прикрепить два файла дополнения .obb по 2 гигабайта. Механизм простой, но сложный при эксплуатации, поэтому лучше всего уложиться в 50 МБ и возрадоваться. И в этом нам помогут целых два архивных формата Zip и 7z.

Давайте рассмотрим их работу на примере уже готового тестового приложения ZipExample.

Для тестов была создана sqlite база данных test_data.db. Она содержит 2 таблицы android_metadata — по традиции и my_test_data с миллионом строчек:

Размер полученного файла составляет 198 МБ.

Сделаем два архива test_data.zip (10.1 МБ) и test_data.7z (3.05 МБ).

Как очевидно, файлы БД sqlite очень хорошо сжимаются. По опыту могу сказать, что чем проще структура базы, тем лучше сжимается. Оба этих файла располагаются в папке assets и в процессе работы будут разархивированы.

Внешний вид программы представляет собой окно с текстом и двумя кнопками:

Вот метод распаковки zip архива:

Распаковывающим классом тут является ZipInputStream он входит в пакет java.util.zip, а тот в свою очередь в стандартную Android SDK и поэтому работает «из коробки» т.е. ничего отдельно закачивать не надо.

Вот метод распаковки 7z архива:

Сначала мы копируем файл архива из asserts , а потом разархивируем при помощи SevenZFile . Он находится в пакете org.apache.commons.compress.archivers.sevenz; и поэтому перед его использованием нужно прописать в build.gradle зависимость: compile ‘org.apache.commons:commons-compress:1.8’.
Android Stuodio сама скачает библиотеки, а если они устарели, то подскажет о наличии обновления.

Вот экран работающего приложения:

Размер отладочной версии приложения получился 6,8 МБ.
А вот его размер в устройстве после распаковки:

Внимание вопрос кто в черном ящике что в кеше?

В заключении хочу сказать, что распаковка архивов занимает продолжительное время и поэтому нельзя его делать в основном (UI) потоке. Это приведет к подвисанию интерфейса. Во избежание этого можно задействовать AsyncTask , а лучше фоновый сервис т.к. пользователь может не дождаться распаковки и выйти, а вы получите ошибку (правда если не поставите костылей в методе onPostExecute).

Буду рад конструктивной критике в комментариях.

Java: недопустимая длина недопустимых кодов Zip?

Когда я пишу записи в ZIP-файл, как это:

Я получаю следующее исключение во втором цикле while:

Кто-нибудь знает, почему выбрасывается это исключение и что это значит?

PS Я должен отметить, что я запускаю это на слушателях на JBoss 7.1.1, чтобы заархивировать различные файлы журналов из разных папок. Там есть ветка для каждой папки. Может ли факт использования нескольких потоков привести к этой проблеме?

1 ответ

Вы устанавливаете ZipEntry нового zip-файла на тот же экземпляр, который вы получили из исходного файла. Это подразумевает, что все значения должны совпадать, но это терпит неудачу, если сжатый размер записанной записи не соответствует сжатому размеру исходного файла. И самое маленькое различие между исходным кодом сжатия и тем, который вы используете сейчас, приведет к разным сжатым размерам. Чтобы запустить его, вы должны создать копию ZipEntry для вывода и сбросить сжатый размер на нем.

PHP | zip_entry_close() Function

The zip_entry_close() function is an inbuilt function in PHP which is used to close a zip archive opened by the zip_entry_open() function. The zip_entry_close() causes the stream to be closed and the connection to the corresponding Zip Archive Entry which may be a file or a directory within the Zip Archive to be broken. The zip entry resource which has to be closed is sent as a parameter to the zip_entry_close() function.

Syntax:

Parameters: The zip_entry_close() function accepts single parameter $zip_entry. It is a mandatory parameter which specifies the zip entry resource.

Return Value: It returns true on success or False on Failure.

Errors And Exceptions:

  • The zip entry archive to be closed must be opened first by using the PHP zip_entry_open() function otherwise the PHP zip_entry_close() function produces a PHP warning.
  • The zip_entry_close() function returns an ER_OPEN error if the zip archive is invalid.
  • The zip_entry_close() function returns an ER_NOZIP error if the zip archive is empty.

Suppose a zip file article.zip contains the following file:
content.xlsx

Below programs illustrate the zip_entry_close() function in PHP:

Архивирование директорий, zip

Java для работы с файлами кроме общего функционала (чтение, запись и т.д.) предоставляет возможность использования zip-архивов. Для этого в пакете java.util.zip определены два класса — ZipInputStream и ZipOutputStream.

При работе с архивами еще в 1999 г. был зарегистрирован баг №4244499, связанный с наименованием файлов, использующие не латинские символы. То есть, наименования файлов с кирилицей искажались. И только в версии JDK 7 этот баг был исправлен — в ZIP API добавили новый конструктор, в котором можно явно указывать кодировку: ZipOutputStream (OutputStream out, Charset charset) К тому же, по-умолчанию используется стандартная UTF-8 кодировка. Таким образом, дополнительных библиотек использовать не нужно, можно сразу делать zip-архив.

К сожалению, мне не удалось создать нормальный архив с русскоязычными символами в наименованиях файлов и директорий. Поэтому в примерах я использовал библиотеку apache-ant-zip.jar, которая успешно решает вопросы архивации файлов, в названии которых используется кириллица.

В качестве примера будем использовать трехуровневую директорию следующей структуры :

Архивирование директории

Для правильной кодировки наименований русскоязычных файлов в примере используется метод setEncoding класса ZipOutputStream.

В примере используется рекурсивный метод addDirectory. В этом мтоде после добавления объекта ZipEntry в поток ZipOutputStream записывается содержимое файла. Для этого используется метод write, записывающий в поток массив байтов zout.write(buffer). В завершении ZipEntry закрывается с помощью метода closeEntry().

Результат работы программы можно увидеть в консоли :

Разархивирование директории

В примере разархивирования используется файл, созданный в предыдущем примере архивирования директории.

Метод Unzip в качестве входного параметра принимает архивный файл. ZipFile позволяет получить все «вхождения» директорий и файлов в архив. После этого в цикле извлекается содержимое архива.

Результат работы программы можно увидеть в консоли :

Работаем с ZIP-архивами средствами MQL5 без использования сторонних библиотек

Оглавление

Введение

Однажды автора данной статьи привлекла интересная особенность функции CryptDecode, а именно — возможность распаковывать переданный ей ZIP-массив. Этот модификатор был введен разработчиками торговой платформы MetaTrader 5 для того, чтобы можно было распаковывать ответ некоторых серверов, используя стандартную функцию WebRequest. Однако из-за некоторых особенностей формата ZIP-файла, использовать ее напрямую было невозможно.

Требовалась дополнительная аутентификация: для распаковки архива необходимо знать его хеш-сумму до упаковки: Adler-32, которой, естественно, не было. Однако, при обсуждении этой проблемы, разработчики пошли навстречу и перегрузили CryptDecode и CryptEncode, ее зеркального близнеца, специальным флагом, игнорирующим хеш Adler32 при распаковке переданных данных. Для неискушенных в техническом плане пользователей это нововведение можно объяснить просто: благодаря ему стала возможной полнофункциональная работа с ZIP-архивами. Эта статья подробно описывает формат ZIP-файла, особенности хранения данных в нем и предлагает для работы с архивом удобный объектно-ориентированный класс CZip.

Для чего это нужно

Сжатие данных — одна из важнейших технологий, особенно распространенная в среде Web. Благодаря сжатию экономятся ресурсы, необходимые для передачи, хранения и обработки информации. Сжатие данных используется практически во всех областях коммуникаций и проникло практически во все задачи, с которыми мы сталкиваемся при работе на компьютере.

Не стала исключением и финансовая сфера: гигабайты тиковой истории, потоки котировок, включая слепки стаканов (Level2-данные), немыслимо хранить в сыром, несжатом виде. Многие серверы, в том числе предоставляющие аналитическую информацию, интересную для торговли, также хранят данных в ZIP-архивах. Раньше не представлялось возможным получать эти данные автоматически, используя штатные средства MQL5. Теперь ситуация изменилась.

С помощью функции WebRequest можно скачать ZIP-архив и на лету распаковать его данные прямо в оперативную память компьютера. Все эти возможности важны и обязательно будут востребованы многими трейдерами. Сжатие данных можно использовать даже для экономии оперативной памяти компьютера. О том, как это делается, посвящен раздел 3.2 данной статьи. Наконец, умение работать с ZIP-архивами открывает доступ к формированию документов типа Microsoft Office по стандарту Office Open XML, что, в свою очередь, сделает возможным создание простых файлов Excel или Word прямо из MQL5, также без использования сторонних DLL библиотек.

Илон Маск рекомендует:  Типы носителей

Как видно, применение ZIP-архивирования обширно, и класс, создаваемый нами, сослужит хорошую службу всем пользователям MetaTrader.

В первой главе данной статьи мы подробно опишем собственно формат ZIP-файла и поймем, из каких блоков данных он состоит. Данная глава будет интересна не только тем, кто изучает MQL, она также послужит хорошим образовательным материалом и тем, кто занимается изучением вопросов, связанных с архивированием и хранением данных. Вторая глава будет посвящена классам CZip, CZipFile и CZipDirectory — эти классы являются основными объектно-ориентированными элементами для работы с архивом. Третья глава описывает практические примеры, связанные с использованием архивирования. Четвертая глава является документацией к предлагаемым классам.

Итак, приступим к изучению этого самого распространенного типа архивирования.

Глава 1. Формат ZIP-файла и способ хранения данных в нем


1.1. Структура ZIP-файла

Формат ZIP был создан Филом Кацом в 1989 году и впервые был реализован в программе PKZIP для MS-DOS, выпущенной компанией PKWARE, основателем которой являлся Кац. Этот формат архива наиболее часто использует алгоритм сжатия данных DEFLATE. Наиболее распространенными программами для работы с этим форматом в среде Windows являются WinZip и WinRAR.

Важно понимать, что формат ZIP-архива развивался со временем и имеет несколько версий. В создании класса для работы с ZIP-архивом, мы будем опираться на официальную спецификацию формата версии 6.3.4, размещенную на сайте компании PKWARE по адресу: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT. Это последняя спецификация формата, датируемая 1 октября 2014 года. Сама спецификация формата достаточно обширна и включает описания множества нюансов.

В данной статье мы будем исходить из принципа наименьших усилий и создадим инструмент, который будет использовать лишь самые необходимые данные для успешной распаковки файлов и создания новых архивов. Это значит, что в определенной мере работа с ZIP-файлами будет ограничена — совместимость форматов не гарантируется, а значит, и не приходится говорить о полной «всеядности» архивов. Вполне возможно, что некоторые ZIP-архивы, созданные сторонними средствами, не смогут быть распакованы с помощью предложенного инструмента.

Каждый ZIP-архив — это бинарный файл, содержащий упорядоченную последовательность байтов. С другой стороны, в ZIP-архиве каждый файл имеет имя, атрибуты (например время модификации файла) и другие свойства, которые мы привыкли видеть в файловой системе любой операционной системы. Поэтому, помимо запакованных данных, каждый ZIP-архив хранит имя запакованного файла, его атрибуты и другую служебную информацию. Эта служебная информация располагается в строго определенном порядке и имеет регулярную структуру. Например, если в архиве содержатся два файла (File#1 и File#2), то архив будет иметь следующую схему:

Рис. 1. Схематичное представление ZIP-архива, содержащего два файла: File#1 и File#2

Позже мы разберем подробно каждый блок данной схемы, а сейчас дадим краткое описание этих блоков:

  • Local File Header — этот блок данных содержит основную информацию о запакованном файле: размер файла до и после упаковки, время модификации файла, контрольную сумму CRC-32 и локальный указатель на имя файла. Кроме того, этот блок содержит версию архиватора, необходимую для распаковки файла.
  • File Name последовательность байтов произвольной длины, образующая имя запакованного файла. При этом длина имени файла не должен превышать 65 536 символов.
  • File Data упакованное содержимое файла в виде байт-массива произвольной длины. Если файл пустой или представляет из себя каталог, то этот массив не используется, и сразу за именем файла или директории идет заголовок Local File Header, описывающий следующий файл.
  • Central Directory содержит расширенное представление данных в Local File Header. Помимо данных, содержащихся в Local File Header, содержит атрибуты файла, локальную ссылку на структуру Local File Header и некоторую другую, в большинстве случаев неиспользуемую информацию.
  • End of central directory record — эта структура представлена в каждом архиве единственным экземпляром и записывается в самый конец архива. Наиболее интересные данные, которые она содержит, это количество записей в архиве (или количество файлов и каталогов) и локальные ссылки на начало блока Central Directory.

Каждый блок данной схемы можно представить либо в виде регулярной структуры, либо в виде байт-массива произвольной длины. Каждую из структур, в свою очередь, можно описать с помощью одноименной конструкции программирования в MQL — структуры.

Структура всегда занимает строго определенное количество байтов, поэтому она не может содержать внутри себя массивы произвольной длины и строки. Однако она может содержать указатели на эти объекты. Именно поэтому названия файлов в архиве вынесены за пределы структуры, благодаря чему они могут иметь произвольную длину. То же относится к упакованным данным файлов — их размер является произвольным, поэтому и они содержатся за пределами структур. Таким образом, можно сказать, что ZIP-архив представляет из себя последовательность структур, строк и упакованных данных.

Формат ZIP-файла, помимо представленного выше, описывает дополнительную структуру, так называемый Data Descriptor. Эта структура используется только в том случае, если по каким-то причинам не удалось сформировать структуру Local File Header, и часть данных, необходимая для Local File Header, стала доступна уже после сжатия данных. На практике это очень экзотическая ситуация, поэтому данная структура практически никогда не используется, и в нашем классе для работы с архивами этот блок данных не поддерживается.

Обратите внимание, что согласно формату ZIP-архива каждый файл сжимается независимо от остальных. С одной стороны, это позволяет локализовать возникновение ошибок: «битый» архив можно восстановить, удалив файл с неправильным содержимым и оставив все остальное содержимое архива без изменений. С другой стороны, при сжатии каждого файла отдельно снижается эффективность сжатия, в особенности если каждый из файлов занимает мало места.

1.2. Изучаем ZIP-файл в шестнадцатеричном редакторе

Теперь, вооружившись самыми необходимыми знаниями, мы можем посмотреть, что находится внутри типичного ZIP-архива. Для этого воспользуемся одним из шестнадцатиричных редакторов, WinHex. Если по каким-то причинам WinHex’а у вас нет, вы можете воспользоваться любым другим шестнадцатиричным редактором. Ведь мы помним, что любой архив — это бинарный файл, который можно открыть как простую последовательность байтов. Для эксперимента создадим простой ZIP-архив, содержащий внутри себя один-единственный текстовый файл с фразой «HelloWorld!» («Привет Мир!»):

Рис. 2. Создание текстового файла в блокноте

Затем воспользуемся любым ZIP-архиватором и с его помощью создадим архив. В нашем примере таким архиватором будет WinRAR. В нем необходимо выбрать только что созданный файл и заархивировать его в формате ZIP:

Рис. 3. Создание архива с помощью архиватора WinRAR

После окончания архивирования на жестком диске компьютера в соответствующей директории появится новый файл «HelloWorld.zip». Первая особенность этого файла которая бросается в глаза — его размер, составляющий 135 байт, он гораздо больше первоначального размера исходного текстового файла в 11 байт. Это связано именно с тем, что помимо собственно упакованных данных, ZIP-архив содержит служебную информацию. Поэтому для небольших данных, занимающих всего несколько сот байтов, архивирование бессмысленно.

Теперь, когда у нас есть схема расположения данных, архив, состоящий из набора байтов, не покажется нам пугающим. Откроем его с помощью шестнадцатеричного редактора WinHex. На рисунке ниже представлен байтовый массив архива с условной подсветкой каждой области, описанной на схеме 1:

Рис. 4. Внутреннее содержимое ZIP-архива, содержащего файл HelloWorld.txt

Собственно фраза «HelloWorld!» содержится в диапазоне с 0x2B по 0x35 байт и занимает всего 11 байт. Обратите внимание, что алгоритм сжатия решил не сжимать исходную фразу, и в ZIP-архиве она присутствует в исходном виде. Это произошло потому, что сжатие такого короткого сообщения неэффективно, и сжатый массив может оказаться даже больше несжатого.

ZIP-архив не во всех случаях содержит сжатые данные. Иногда данные в архиве располагаются в исходном, несжатом виде, даже если при создании архива было явно указано сжимать данные при архивировании. Эта ситуация возникает в случае, когда размер данных незначителен, и сжатие данных неэффективно.

Благодаря рисунку 4 становится понятным, как разные блоки данных хранятся в получившемся архиве, и где именно содержатся данные файла. Теперь настало время подробно разобрать каждый из блоков данных в отдельности.

1.3. Структура Local File Header

Каждый ZIP-архив начинается со структуры Local File Header. Она содержит метаданные файла, следующего за ней в виде сжатого байтового массива. Каждая структура в архиве, согласно спецификации формата, имеет свой уникальный четырехбайтовый идентификатор. Не является исключением и эта структура, ее уникальный идентификатор равен 0x04034B50 .

Важно учитывать, что x86-совместимые процессоры загружают данные из бинарных файлов в оперативную память в обратном порядке. Числа при этом располагаются наизнанку: последний байт занимает место первого и наоборот. Способ записи данных в файл определяется форматом самого файла и для файлов в формате ZIP также осуществляется в обратном порядке. Более подробно о порядке следования байтов можно почитать в одноименной статье на Wikipedia: «Порядок байтов». Для нас же это означает, что идентификатор структуры будет записан в виде числа 0x504B0304 (значения 0x04034B50, вывернутого наизнанку). Именно с этой последовательности байтов начинается любой ZIP-архив.

Поскольку структура — это строго определенная последовательность байтов, ее можно представить в виде аналогичной структуры на языке программирования MQL5. Описание структуры Local File Header на MQL5 будет следующим:

Данная структура используется для реальной работы с ZIP-архивами, поэтому помимо собственно полей данных, содержит дополнительные методы, позволяющие конвертировать структуру в набор байтов (байтовый массив uchar) и, наоборот, создавать структуру из набора байтов. Приведем содержимое методов ToCharArray и LoadFromCharArray, позволяющих делать такое преобразование:

Опишем поля структуры (перечислены в порядке следования):

  • header — уникальный идентификатор стркутуры, для File Local Header равен 0x04034B50 ;
  • version — минимальная версия для распаковки файла;
  • bit_flag — битовый флаг, имеет идентификатор 0x02 ;
  • comp_method — тип используемого сжатия. Как правило, всегда используется метод сжатия DEFLATE, этот тип сжатия имеет идентификатор 0x08 .
  • last_mod_time — время последней модификации файла. Содержит часы, минуты и секунды модификации файла в формате MS-DOS. Этот формат описан на странице компании Microsoft.
  • last_mod_date — дата последней модификации файла. Содержит день месяца, номер месяца в году и год модификации файла в формате MS-DOS.
  • crc_32 — контрольная сумма CRC-32. Используется программами по работе с архивами для определения ошибок содержимого файла. Если это поле не заполнено, ZIP-архиватор откажется распаковывать упакованный файл, ссылаясь на испорченный файл.
  • comp_size — размер в байтах упакованных данных;
  • uncomp_size — размер в байтах исходных данных;
  • filename_length — длина имени файла;
  • extrafield_length — специальное поле для записи дополнительных атрибутов данных. Практически никогда не используется и равно нулю.

При сохранении этой структуры в архиве создается последовательность байтов, хранящая значения соответствующих полей этой структуры. Снова загрузим наш ZIP-архив с файлом HelloWorld.txt в шестнадцатеричный редактор и разберем байтовый массив этой структуры уже подробно:

Рис. 5. Байт-схема структуры Local File Header в архиве HelloWorld.zip

Из схемы видно, какие байты занимают те или иные поля структуры. Для проверки данных в ней обратим внимание на поле «File Name length», оно занимает два байта и равно значению 0x0D00 . Вывернув это число наизнанку и переведя его в десятичный формат, мы получим значение 13 — именно столько символов занимает имя файла «HelloWorld.txt». То же самое можем проделать с полем, указывающим размер сжатых данных. Оно равно 0x0B000000 , что соответствует 11 байтам. В самом деле, фраза «HelloWorld!» хранится в архиве в несжатом виде и занимает 11 байт.

Сразу после структуры идут сжатые данные, а затем начинается новая структура: Central Directory, ее мы опишем более подробно в следующем разделе.

1.4. Структура Central Directory

Структура Central Directory представляет собой расширенное представление данных, находящихся в Local File Header. По сути, для основной работы с ZIP-архивами достаточно данных из Local File Header. Тем не менее, использование структуры Central Directory является обязательным, и ее значения должны быть корректно заполнены. Эта структура имеет свой уникальный идентификатор 0x02014B50 . На MQL5 ее представление будет следующим:

Как видно, она содержит уже больше данных, однако большая часть из них дублирует данные Local File Header. Так же как и предыдущая структура, она содержит сервисные методы по конвертации своего содержимого в байт-массив и обратно.

  • header — уникальный идентификатор структуры, равен 0x02014B50 ;
  • made_ver — версия стандарта архивирования, используемого при архивировании;
  • version — минимальная версия стандарта для успешной распаковки файла;
  • bit_flag — битовый флаг, имеет идентификатор 0x02 ;
  • comp_method — тип используемого сжатия. Как правило, всегда используется метод сжатия DEFLATE, этот тип сжатия имеет идентификатор 0x08 .
  • last_mod_time — время последней модификации файла. Содержит часы, минуты и секунды модификации файла в формате MS-DOS. Этот формат описан на странице компании Microsoft.
  • last_mod_date — дата последней модификации файла. Содержит день месяца, номер месяца в году и год модификации файла в формате MS-DOS.
  • crc_32 — контрольная сумма CRC-32. Используется программами по работе с архивами для определения ошибок содержимого файла. Если это поле не заполнено, ZIP-архиватор откажется распаковывать упакованный файл, ссылаясь на испорченный файл.
  • comp_size — размер в байтах упакованных данных;
  • uncomp_size — размер в байтах исходных данных;
  • filename_length — длина имени файла;
  • extrafield_length — специальное поле для записи дополнительных атрибутов данных. Практически никогда не используется и равно нулю.
  • file_comment_length — длина комментария к файлу;
  • disk_number_start — номер диска, в который записывается архив. Практически всегда равен нулю.
  • internal_file_attr — атрибуты файла в формате MS-DOS;
  • external_file_attr — расширенные атрибуты файла в формате MS-DOS;
  • offset_header — адрес, по которому располагается начало структуры Local File Header.

При сохранении этой структуры в архиве создается последовательность байтов, хранящая значения ее полей. Приведем схему расположения байтов этой структуры, подобно рисунку 5:

Рис. 6. Байт-схема структуры Central Directory в архиве HelloWorld.zip

В отличие от Local File Header, структуры Central Directory идут последовательно друг за другом. Адрес начала первой из них указан в специальном завершающем блоке данных — структуре ECDR. Более подробно эту структуру мы опишем в следующем разделе.

1.5. Структура End of Central Directory Record (ECDR)

Структура End of Central Directory Record (или просто ECDR) завершает ZIP-файл. Ее уникальный идентификатор равен 0x06054B50 . В каждом архиве она содержится в единственном экземпляре. ECDR хранит количество файлов и директорий, находящихся в архиве, а также адрес начала последовательности структур Central Directory и их суммарный размер. Помимо этого, блок данных хранит и другие сведения. Приведем полное описание ECDR на MQL5:

Опишем поля этой структуры более подробно:

  • header — уникальный идентификатор структуры, равен 0x06054B50;
  • disk_number — номер диска;
  • disk_number_cd — номер диска, с которого начинается Central Directory;
  • total_entries_disk — всего записей в секции Central Directory (количество файлов и директорий);
  • total_entries — всего записей (количество файлов и директорий);
  • size_central_dir — размер секции Central Directory;
  • start_cd_offset — байт-адрес начала секции Central Directory;
  • file_comment_length — длина комментария к архиву.

При сохранении этой структуры в архиве создается последовательность байтов, хранящая значения ее полей. Приведем схему расположения байтов этой структуры:

Рис. 7. Байт-схема структуры ECDR

Этот блок данных будет использован нами при определении количества элементов в массиве.

Глава 2. Обзор класса CZip и его алгоритмов

2.1. Структура упакованных файлов в архиве, классы CZipFile и CZipFolder

Итак, в первой главе мы подробно разобрали формат ZIP-архива. Мы рассмотрели, из каких типов данных он состоит, и описали эти типы в соответствующих структурах. Определив эти типы, мы реализуем высокоуровневый специализированный класс CZip, с помощью которого можно будет легко и просто совершать следующие действия с ZIP-архивом:

  • Создавать новый архив;
  • Открывать ранее созданный архив на жестком диске;
  • Загружать архив с удаленного сервера;
  • Добавлять новые файлы в архив;
  • Удалять файлы из архива;
  • Распаковывать архив как полностью, так и отдельные его файлы.

Класс CZip возьмет на себя правильное заполнение необходимых структур в архиве, предоставляя нам привычный высокоуровневый интерфейс для работы с файловой коллекцией архива. Возможностей, предоставляемых классом, будет более чем достаточно для подавляющего большинства задач, связанных с архивированием.

Очевидно, что содержимое ZIP-архива можно разделить на папки и файлы. Оба типа содержимого имеют обширный набор свойств: имя, размер, атрибуты файла, время создания и т.д. Некоторые из этих свойств являются общими как для папок, так и для файлов, а некоторые, как, например, упакованные данные, нет. Поэтому оптимальным решением для работы с архивом будет предоставление специальных служебных классов: CZipFile и CZipDirectory. Именно эти классы будут представлять файлы и папки соответственно. Условная классификация содержимого в архиве приведена на схеме ниже:

Рис. 8. Условная классификация объектов в архиве

Таким образом, чтобы добавить файл в архив CZip, необходимо вначале создать объект типа CZipFile, а затем добавить этот объект-файл в архив. В качестве примера создадим текстовый файл «HelloWorld.txt», содержащий одноименный текст «HelloWorld!» и добавим его в архив:

После выполнения этого кода на диске компьютера появится новый ZIP-архив, содержащий единственный текстовый файл «HelloWorld.txt» с одноименной фразой. Если бы мы захотели создать папку вместо файла, то вместо CZipFile нам необходимо было бы создать экземпляр класса CZipFolder. Для его создания достаточно было бы указать только имя.

Как уже было сказано, классы CZipFile и CZipFolder имеют много общего. Поэтому оба класса наследуются от их общего прародителя — CZipContent. Этот класс содержит общие методы и данные для работы с содержимым архива.

2.2. Создание упакованных файлов с помощью CZipFile

Создание упакованного ZIP-файла тождественно созданию экземпляра CZipFile. Как известно, чтобы создать файл, необходимо указать его имя и содержимое. Поэтому конструктор CZipFile также требует явного указания соответствующих параметров:

В разделе 2.1 был показан вызов именно этого конструктора.

Кроме того, иногда требуется не создавать файл, а загрузить уже имеющийся файл с диска. Для этого случая в классе CZipFile существует второй конструктор, позволяющий создать ZIP-файл на основе обычного файла на жестком диске:

Вся работа в этом конструкторе делегируется приватному методу AddFile. Алгоритм его работы следующий:

  1. Открывается указанный файл для чтения, его содержимое считывается в байт-массив.
  2. Полученный байт-массив упаковывается методом AddFileArray и хранится в специальном динамическом массиве типа uchar.

Метод AddFileArray является «сердцем» всей системы классов для работы с архивами. Ведь именно в этом методе находится самая важная системная функция — CryptEncode. Приведем исходный код этого метода:

Желтым цветом указано конфигурирование функции CryptEncode c последующем архивированием байт-массива. Таким образом, можно сделать вывод, что упаковка файла происходит в момент создания объекта CZipFile, а не в момент создания или сохранения самого ZIP-архива, как можно было бы подумать. Благодаря этому свойству все данные, переданные в класс CZip, автоматически сжимаются, а значит, требуют для своего хранения меньше оперативной памяти.

Обратите внимание, что во всех случаях в качестве данных используется беззнаковый байт-массив uchar. В самом деле, все данные, которыми мы оперируем на компьютере, можно представить как некую последовательность байтов. Поэтому для создания действительно универсального контейнера сжатых данных, чем CZipFile и является по своей сути, был выбран беззнаковый массив uchar.

Пользователю необходимо самостоятельно сконвертировать данные для хранения в архиве в беззнаковый массив uchar[], который, в свою очередь, также необходимо передать по ссылке в качестве содержимого файла для класса CZipFile. Благодаря этой особенности в ZIP-архиве может располагаться абсолютно любой тип файлов, как загруженный с диска, так и созданный в процессе работы MQL-программы.

Распаковка данных является более тривиальной задачей. Для распаковки данных в исходный байт массив file_array используется метод GetUnpackFile, который по сути является методом-обложкой для системной функции CryptDecode:

2.3. Вспоминаем MS-DOS. Формат времени и даты в ZIP-архиве

Формат хранения данных ZIP создавался в конце 80-ых годов прошлого века для платформы MS-DOS, «правопреемником» которой стала Windows. В то время ресурсы для хранения данных были ограничены, поэтому дату и время ОС MS-DOS хранила отдельно: два байта (или машинное слово для 16-разрядных процессоров того времени) выделялось для даты и два байта для времени. Причем самая ранняя дата, которая могла быть представлена этим форматом, была 1 января 1980 года (01.01.1980). Минуты, часы, дни, месяцы и годы занимали определенные диапазоны битов в машинном слове, и для того чтобы извлечь или записать их, по-прежнему приходится прибегать к битовым операциям.

Приведем формат хранения даты в соответствующем двухбайтовом поле:

№ битов Описание
0-4 День месяца (0-31)
5-8 Номер месяца (1 — январь, 2 — февраль и т.д.)
9-15 Номер года начиная с 1980

Таблица 1. Формат хранения даты в двухбайтовом поле

Аналогично, приведем формат хранения времени в соответствующем двухбайтовом поле:

№ битов Описание
0-4 Секунды (точностью хранения +/- 2 секунды)
5-10 Минуты (0-59)
11-15 Часы в 24-часовом формате

Таблица 2. Формат хранения времени в двухбайтовом поле

Зная спецификацию данного формата и умея работать с битовыми операциями, можно написать соответствующие функции, конвертирующие дату и время в формате MQL в формат MS-DOS. Можно также написать обратные процедуры. Такие методы конвертации общие как для папок, представленных CZipFolder, так и для файлов, представленных CZipFile. Задавая таким образом дату и время для них в привычном MQL формате, мы «за кулисами» конвертируем этот тип данных в формат MS-DOS. Таким конвертированием занимаются методы DosDate, DosTime, MqlDate и MqlTime. Приведем их исходный код.

Конвертация даты формата MQL в формат даты MS-DOS:

Конвертация даты в формате MS-DOS в формат MQL:

Конвертация времени формата MS-DOS в формат времени MQL:

Конвертация времени формата MS-DOS в формат времени MQL:

Данные методы используют внутренние переменные для хранения даты и времени: m_directory.last_mod_time и m_directory.last_mod_date, где m_directory — структура типа Central Directory.

2.4. Генерация контрольной суммы CRC-32

Интересной особенностью формата ZIP-архива является хранение, помимо служебных данных, специальной информации для восстановления, которая в некоторых случаях помогает восстановить поврежденные данные. Для того чтобы понять, являются ли полученные данные целыми или поврежденными, в ZIP-архиве содержится специальное дополнительное поле, хранящее двухбайтовое значение специального хеша CRC-32. Это контрольная сумма, которая рассчитывается для данных до упаковки. Архиватор, распаковав данных из архива, заново рассчитывает эту контрольную сумму, и если она не совпадает, считает, что данные повреждены и не могут быть предоставлены пользователю.

Таким образом, нашему классу CZip необходимо иметь свой собственный алгоритм расчета CRC-32. В противном случае архивы, созданные нашим классом, откажутся читать сторонние средства для работы с ними, например WinRAR выдаст ошибку-предупреждение о поврежденных данных:

Рис. 9. Предупреждение архиватора WinRAR о повреждении данных файла «HelloWorld.txt»

Поскольку контрольная сумма CRC-32 требуется только для файлов, метод, рассчитывающий эту сумму, представлен лишь в классе CZipFile. Метод реализован на основе примера на языке программирования Си, приведенного в статье по адресу: https://ru.wikibooks.org/wiki/Реализации_алгоритмов/Циклический_избыточный_код:

Чтобы убедиться в правильности работы метода, достаточно открыть архив, созданный с помощью CZip, в архиваторе WinRAR. Каждый файл будет иметь свой уникальный код CRC-32:

Рис. 10. Контрольная сумма CRC-32 в окне архиватора WinRAR

Файлы с корректным CRC-32 хешем архиватор распаковывает в штатном режиме, без появления соответствующих предупреждающих сообщений.

2.5. Чтение и запись архива

Последнее, что мы разберем, будут методы для чтения и записи самого ZIP-архива. Очевидно, что если у нас есть коллекция, например CArrayObj, состоящая из элементов CZipFile и CZipFolder, задача по формированию самого архива будет тривиальной. Достаточно каждый элемент сконвертировать в байт-последовательность и записать ее в файл. Этими задачами занимаются следующие методы:

  • SaveZipToFile — открывает указанный файл и записывает в него сгенерированный байт-массив архива.
  • ToCharArray — создает соответствующую байтовую структуру архива. Генерирует завершающую структуру ECDR.
  • ZipElementsToArray — преобразует элемент типа CZipContent в последовательность байтов.

Единственная сложность состоит в том, что каждый элемент архива, представленный типом CZipContent, хранится в двух разных частях файла, в структурах Local File Header и Central Directory. Поэтому необходимо использовать специальный вызов метода ZipElementsToArray, который в зависимости от переданного ему модификатора ENUM_ZIP_PART выдает либо байтовый массив типа Local File Header, либо Central Directory.

Теперь, учитывая эту особенность, нам должно быть понятно содержимое этих трех методов, исходный код которых представлен ниже:

Загрузка архива также обладает некоторыми нюансами. Очевидно, что загрузка архива — операция, обратная сохранению. Если при сохранении архива элементы типа CZipContent преобразуются в байтовую последовательность, то при загрузке архива байтовая последовательность преобразуется в элементы типа CZipContent. И снова, из-за того, что каждый элемент в архиве хранится в двух разных частях файла — Local File Header и Central Directory, элемент CZipContent за одно чтение данных создать невозможно.

Необходимо использовать промежуточный класс-контейнер CSourceZip, в который вначале последовательно добавляются нужные элементы, а затем на его основе формируется нужный тип данных — CZipFile или CZipFolder. Именно поэтому эти два класса имеют дополнительный конструктор, принимающий в качестве ссылочного параметра указатель на элемент типа CSourceZip. Данный вид инициализации, как и сам класс CSourceZip, создавался исключительно для служебного использования классом CZip, и его не рекомендуется использовать в явном виде.

За саму загрузку ответственны три метода класса CZip:

  • LoadZipFromFile — открывает указанный файл и читает его содержимое в байт-массив.
  • LoadHeader — загружает по предложенному адресу из байтового массива архива структуру Local File.
  • LoadDirectory — загружает по предложенному адресу из байтового массива архива структуру Central Directory.

Итак, приведем исходный код этих методов:

Глава 3. Примеры использования класса CZip, измерение производительности

В предыдущей главе мы рассмотрели класс CZip и собственно формат данных ZIP-архива. Теперь, зная устройство архива, а также общие принципы работы с классом CZip, мы можем перейти к рассмотрению практических задач, связанных с архивированием. В данной главе подробно рассмотрены три разносторонних примера, которые наиболее полно охватывают весь спектр задач этого класса.

3.1. Создание ZIP-архива с котировками по всем выбранным символам

Первая задача, которую часто требуется решать, это сохранение ранее полученных данных. Часто данные получаются в самом терминале MetaTrader. Такими данными могут быть последовательность накопленных тиков или котировки в формате OHLCV. Мы рассмотрим задачу, когда котировки требуется сохранить в специальные CSV-файлы, формат которых будет следующим:

Это текстовый формат данных. Он часто используется для передачи данных между разными системами статистического анализа. Формат текстовых файлов, к сожалению, обладает большой избыточностью хранения данных, так как в каждом байте используется лишь очень ограниченное количество знаков. Как правило, это знаки пунктуации, цифры, заглавные и строчные буквы алфавита. Кроме того, многие значения в этом формате часто повторяются, например, дата или цена открытия, как правило, одна и та же для большого массива данных. Поэтому сжатие этого типа данных должно быть эффективным.

Итак, давайте напишем скрипт, загружающий необходимые данные из терминала. Его алгоритм будет следующим:

  • Последовательно выбираются инструменты, размещенные в окне Market Watch.
  • По каждому выбранному инструменту запрашиваются котировки для каждого из 21 таймфрейма.
  • Котировки выбранного таймфрейма конвертируются в массив CSV строк.
  • Массив CSV строк конвертируется в байтовый массив.
  • Создается ZIP-файл (CZipFile), содержащий байтовый массив котировок, после чего он добавляется в архив.
  • После создания всех файлов котировок архив CZip сохраняется на диске компьютера в файл Quotes.zip.

Исходный код скрипта, выполняющий эти действия, представлен ниже:

Загрузка данных может занимать существенное время, поэтому в окне Market Watch были выбраны только четыре символа. Кроме того, мы загрузим лишь сто последних известных баров. Это тоже должно сократить время выполнения скрипта. После его выполнения в папке общих файлов MetaTrader появился архив Quotes.zip. Его содержимое можно увидеть в любой программе по работе с архивами, например WinRAR:

Рис. 11. Сохраненные файлы котировок, просматриваемые в архиваторе WinRAR

Созданный архив сжат втрое по сравнению с исходным размером. Об этом нам сообщает сам архиватор WinRAR:

Рис. 12. Степень сжатия сгенерированного архива в информационном окне WinRAR

Это хороший результат сжатия. Однако еще лучшего коэффициента сжатия удалось бы добиться на больших и немногочисленных файлах.

Пример скрипта, создающий котировки и сохраняющий их в zip архив прикреплен к данной статье под именем ZipTask1.mq5 и находится в папке Scripts.

3.2. Загрузка архива с удаленного сервера на примере сайта MQL5.com

Следующая рассматриваемая задача будет сетевой. Наш пример продемонстрирует, как можно загружать ZIP-архивы с удаленных серверов. В качестве примера мы произведем загрузку индикатора Alligator, находящегося в базе исходных кодов Code Base по адресу https://www.mql5.com/ru/code/9:

Для каждого опубликованного в Code Base индикатора, советника, скрипта или библиотеки существует архивная версия, где все исходные коды продукта упакованы в единый архив. Именно эту архивную версию мы скачаем и распакуем на локальном компьютере. Но прежде чем это сделать, необходимо поставить разрешение на доступ к mql5.com, для чего в окне Сервис Настройки Советники необходимо вписать адрес «https://www.mql5.com» в список разрешенных серверов.

Класс CZip обладает собственным методом для загрузки архивов с интернет-ресурсов. Но вместо его использования давайте напишем собственный скрипт, совершающий такую загрузку:

Как видите, исходный код скрипта довольно простой. Вначале вызывается WebRequest с адресом удаленного ZIP-архива. WebRequest закачивает байт-массив архива в результирующий массив zip_array, после чего он загружается в класс CZip посредством метода CreateFromCharArray. Этот метод позволяет создать архив прямо из последовательности байтов, что бывает иногда необходимым при внутренней работе с архивами.

Помимо метода CreateFromCharArray, CZip содержит специальный метод LoadZipFromUrl для загрузки архивов по интернет-ссылке. Он работает примерно так же, как и наш предыдущий скрипт. Приведем его исходный код:

Результат работы этого метода будет аналогичным: через некоторое время будет создан ZIP-архив, содержимое которого будет скачано с удаленного сервера.

Пример скрипта, загружающий архив из CodeBase прикреплен к данной статье под именем ZipTask2.mq5 и находится в папке Scripts.

3.3. Сжатие служебных данных программы в оперативной памяти компьютера

Сжатие внутренних данных программы в оперативной памяти компьютера — нетривиальный способ использования архивирования. Этот способ можно использовать, когда обрабатываемых данных слишком много для размещения в оперативной памяти. Однако при использовании данного подхода общая производительность программы снизится, ведь потребуются дополнительные действия по архивированию/разархивированию служебных структур или данных.

Предположим, что MQL-программе необходимо хранить коллекцию исторических ордеров. Каждый ордер будет описываться специальной структурой Order, которая будет содержать все его свойства: идентификатор, тип ордера, время исполнения, объем и т.д. Опишем данную структуру:

Вызов оператора sizeof показывает, что данная структура занимает 200 байт. Таким образом, хранение коллекции исторических ордеров занимает количество байт, рассчитанное по формуле: sizeof(Order) * количество исторических ордеров. Следовательно, для коллекции, насчитывающей 1000 исторических ордеров, потребуется выделение памяти 200 * 1000 = 200 000 байт или почти 200 Кбайт. Это немного по современным меркам, однако в случае, когда размер коллекции будет превышать десятки тысяч элементов, объем занимаемой памяти будет существенен.

Тем не менее, можно разработать специальный контейнер для хранения этих ордеров, который бы позволял сжимать их содержимое. Этот контейнер, помимо обычных методов добавления и удаления новых элементов Order, также будет содержать методы Pack и Unpack, сжимающие содержимое структур типа Order. Приведем исходный код данного контейнера:

Идея в том, что пользователь может добавлять новые элементы в контейнер, а также, в случае необходимости, сжимать его содержимое прямо в оперативной памяти компьютера. Посмотрим, как это работает. Напишем демонстрационный скрипт:

Момент сжатия коллекции в нем выделен желтым маркером. Запущенный на одном из счетов, насчитывающем 858 исторических ордеров, данный скрипт выдал следующие результаты:

Как видно, размер неупакованной коллекции составил 171 600 байт. После упаковки размер коллекции был равен всего 1 521 байт. Т.е. степень компрессии превысила сто раз! Это объясняется тем, что многие поля структуры содержат похожие данные. Также многие поля имеют пустые значения, под которые, тем не менее, выделяется память.

Чтобы убедиться, что сжатие действительно работает корректно, достаточно выбрать любой ордер из коллекции и распечатать его свойство. Нами был выбран первый ордер и его уникальный идентификатор. После упаковки идентификатор ордера отобразился верно:

Описываемый алгоритм в случае обращения к своей коллекции распаковывает ранее упакованные данные. Это снижает производительность. Поэтому сжимать данные нужно только после того, как работа по их формированию завершена. Для лучшей степени сжатия все данные собираются в единый массив, а затем упаковываются. Для распаковки происходит обратный процесс.

Интересно, что упаковка 858 элементов занимает около 2.5 миллисекунд на достаточно мощном компьютере. Распаковка этих же данных происходит еще быстрее и занимает порядка 0.9 миллисекунды. Таким образом, на один цикл упаковки/распаковки массива, состоящего из тысячи элементов, тратится примерно 3.5-4.0 миллисекунды. При этом достигается более чем стократная экономия памяти. Такие характеристики смотрятся достаточно впечатляюще, чтобы использовать ZIP-сжатие для организации больших массивов данных.

Пример скрипта, сжимающего данные в оперативной памяти, прикреплен к данной статье под именем ZipTask3.mq5 и находится в папке Scripts. Для его работы также необходим файл Orders.mqh, располагающийся в папке Include.

Глава 4. Документация к классам для работы с ZIP-архивами

4.1. Документация к классу CZipContent

В данной главе описаны методы и перечисления, используемые в классах для работы с ZIP-архивами. На уровне пользователей класс CZipContent не используется напрямую, однако все его открытые методы делегируются классам CZipFile и CZipFolder, таким образом, свойства и методы, описанные в нем, распространяются также и на эти классы.

Метод ZipType возвращает тип текущего элемента в архиве. Типов элементов, хранимых в архиве, два: папка (директория) и файл. Тип папки представлен классом CZipDirectory, тип файла представлен классом CZipFile. Более подробно о типах ZIP-архива можно прочитать в разделе 2.1 текущей главы: «Структура упакованных файлов в архиве, классы CZipFile и CZipFolder».

Возвращает перечисление ENUM_ZIP_TYPE, описывающее, к какому типу принадлежит текущий экземпляр CZipContent.

Возвращает название папки или файла в архиве.

Имя файла или папки.

Метод Name(string name)

Устанавливает название текущей папки или файла в архиве. Используется в случаях, когда требуется изменить имя текущей папки или файла.

  • [in] name — новое имя папки или файла. Имя должно быть уникальным и не иметь совпадений среди других имен папок и файлов в архиве.

Метод CreateDateTime(datetime date_time)

Устанавливает новую дату изменения папки или файла в архиве.

  • [in] date_time — дата и время, которое требуется установить для текущей папки или файла.

Дата и время конвертируются в формат MS-DOS и хранятся во внутренних структурах типа ZipLocalHeader и ZipCentralDirectory. Подробнее о способах конвертирования и представления этого формата описано в разделе 2.3 данной статьи: «Вспоминаем MS-DOS. Формат времени и даты в ZIP-архиве».

Возвращает дату и время изменения текущей папки или файла.

Дата и время изменения текущей папки или файла.

Возвращает размер упакованных данных в файле. Для директорий размер упакованных данных всегда равен нулю.

Размер упакованных данных в байтах.

Возвращает размер исходных, неупакованных данных в файле. Для директорий размер неупакованных данных всегда равен нулю.

Размер исходных данных в байтах.

Возвращает суммарный размер элемента архива. Каждый файл или директория в архиве, помимо своего названия и содержимого (для файлов), хранит дополнительные служебные структуры, размер которых также учитывается при расчете суммарного размера элемента архива.

Суммарный размер текущего элемента в архиве, учитывающий дополнительные служебные данные.

Возвращает длину имени директории или файла, выраженную в количестве используемых символов.

Длина имени директории или файла, выраженная в количестве используемых символов.

Распаковывает содержимое элемента и сохраняет его в файле с именем элемента на жестком диске компьютера. Если распаковывается директория, то вместо файла создается соответствующая папка.

  • [in] folder — имя корневой папки, в которую требуется распаковать текущую папку или файл. Если элемент требуется распаковать без создания папки архива, то это значение необходимо оставить пустым, равным «».
  • [in] file_common — этот модификатор указывает, в какой секции файловой системы программ MetaTrader необходимо распаковать элемент. Установите этот параметр равным FILE_COMMON, если хотите выполнить распаковку в общий файловый раздел всех терминалов MetaTrader 5.

Возвращает истину, если распаковка файла или папки на жесткий диск прошла успешно. Возвращает ложь в противном случае.

4.2. Документация к классу CZipFile

Класс CZipFile наследуется от CZipContent и используется для хранения файлов в архиве. CZipFile хранит содержимое файла только в упакованном виде. Это значит, что при передаче ему файла для хранения происходит автоматическая упаковка его содержимого. Распаковка файла также происходит в автоматическом режиме при вызове метода GetUnpackFile. Помимо ряда поддерживаемых методов CZipContent, CZipFile также поддерживает специальные методы для работы с файлами. Далее приведены описания этих методов.

Добавляет файл с жесткого диска в текущий элемент CZipFile. Для того чтобы добавить файл в архив типа CZip, вначале необходимо создать экземпляр класса CZipFile, указав при создании название файла и путь к нему. После того как экземпяляр класса будет создан, его необходимо будет добавить в класс CZip, вызвав соответствующий метод. Фактическая упаковка переданного содержимого происходит в момент его добавления (вызова данного метода).

  • [in] full_path — полное имя файла, включая путь к нему относительно центрального каталога файлов программ MQL.
  • [in] file_common — этот модификатор указывает, в какой секции файловой системы программ MetaTrader необходимо распаковать элемент. Установите этот параметр равным FILE_COMMON, если хотите выполнить распаковку в общий файловый раздел всех терминалов MetaTrader 5.

Возвращает истину, если добавление файл прошло успешно. Возвращает ложь в противном случае.

Добавляет в качестве содержимого CZipFile массив байтов типа uchar. Данный метод используется в случае динамического создания содержимого файла. Фактическая упаковка переданного содержимого происходит в момент его добавления (вызова данного метода).

  • [in] file_src — байтовый массив, который необходимо добавить.

Возвращает истину, если добавление файл прошло успешно. Возвращает ложь в противном случае.

Возвращает упакованное содержимое файла.

  • [out] file_array — байтовый массив, в который требуется принять упакованное содержимое файла.

Возвращает распакованное содержимое файла. Содержимое распаковывается в момент обращения к методу.

  • [out] file_array — байтовый массив, в который требуется принять распакованное содержимое файла.

4.3. Документация к классу CZip

Класс CZip реализует основную работу с архивами типа ZIP. Класс представляет собой обобщенный архив ZIP, в который могут быть добавлены ZIP-элементы двух типов: элементы, представляющие папку (CZipDirectory), и элементы, представляющие ZIP-файлы (CZipFile). Помимо прочего, класс CZip позволяет загружать уже существующие архивы, как с жесткого диска компьютера, так и в виде байт-последовательности.

Конвертирует содержимое ZIP-архива в байтовую последовательность типа uchar.

  • [out] zip_arch — байтовый массив, в который требуется принять содержимое ZIP-архива.

Загружает ZIP-архив из байтовой последовательности.

  • [out] zip_arch — байтовый массив, из которого требуется загрузить содержимое ZIP-архива.

Истина, если создание архива из байтовой последовательности прошло успешно, и ложь в противном случае.

Сохраняет текущий ZIP-архив с его содержимым в указанный файл.

  • [in] zip_name — полное имя файла, включая путь к нему относительно центрального каталога файлов программ MQL.
  • [in] file_common — этот модификатор указывает, в какой секции файловой системы программ MetaTrader необходимо распаковать элемент. Установите этот параметр равным FILE_COMMON, если хотите выполнить распаковку в общий файловый раздел всех терминалов MetaTrader 5.

Истина, если сохранение архива в файл прошла успешно, и ложь в противном случае.

Загружает содержимое архива из файла на жестком диске компьютера.

  • [in] full_path — полное имя файла, включая путь к нему относительно центрального каталога файлов программ MQL.
  • [in] file_common — этот модификатор указывает, в какой секции файловой системы программ MetaTrader необходимо распаковать элемент. Установите этот параметр равным FILE_COMMON, если хотите выполнить распаковку в общий файловый раздел всех терминалов MetaTrader 5.

Истина, если загрузка архива из файла прошла успешно, и ложь в противном случае.

Загружает содержимое архива по интернет-ссылке url. Для корректной работы данного метода необходимо выставить разрешение для доступа к запрашиваемому ресурсу. Более подробно работа этого метода описана в разделе 3.2 данной статьи: «Загрузка архива с удаленного сервера на примере сайта MQL5.com»

Распаковывает все файлы и директории текущего архива в предложенный каталог.

  • [in] folder — папка, в которую необходимо распаковать текущий архив. Если папку для архива создавать не требуется, в качестве параметра необходимо передать пустое значение «».
  • [in] file_common — этот модификатор указывает, в какой секции файловой системы программ MetaTrader необходимо распаковать элемент. Установите этот параметр равным FILE_COMMON, если хотите выполнить распаковку в общий файловый раздел всех терминалов MetaTrader 5.

Истина, если распаковка архива прошла успешно, и ложь в противном случае.

Возвращает размер архива в байтах.

Размер архива в байтах.

Возвращает количество элементов в архиве. Элементом архива может быть директория либо запакованный файл.

Количество элементов в архиве.

Добавляет новый ZIP-файл в текущий архив. Файл должен быть представлен в виде CZipFile и создан предварительно, до добавления в архив.

  • [in] file — ZIP-файл, который требуется добавить в архив.

Истина, если добавление в архив прошло успешно, и ложь в противном случае.

Удаляет файл типа CZipFile по индексу index из архива.

  • [in] index — индекс файла, который требуется удалить из архива.

Истина, если удаление файла из архива прошло успешно. Ложь в противном случае.

Получает элемент типа CZipFile, размещенный по индексу index.

  • [in] index — индекс файла, который требуется получить из архива.

Элемент типа CZipFile, который располагается по индексу index.

4.4. Структура ENUM_ZIP_ERROR и получение расширенной информации об ошибках

В процессе работы с классами CZip, CZipFile и CZipDirectory могут возникать различные ошибки, например ошибка, возникающая при попытке доступа к несуществующему файлу и т.д. Большинство методов, представленных в этих классах, возвращают соответствующий флаг типа bool, сигнализирующий об успешности совершения операции. В случае возвращения отрицательного значения (false) можно получить дополнительную информацию о причинах сбоя. Причинами сбоя могут быть как стандартные, системные ошибки, так и специфические ошибки, возникающие в процессе работы с ZIP-архивом. Для передачи специфических ошибок используется механизм передачи пользовательских ошибок с помощью функции SetUserError. Коды пользовательских ошибок задаются перечислением ENUM_ZIP_ERROR:

Значение Описание
ZIP_ERROR_EMPTY_SOURCE Файл, переданный для упаковки, пустой.
ZIP_ERROR_BAD_PACK_ZIP Ошибка внутреннего упаковщика/распаковщика.
ZIP_ERROR_BAD_FORMAT_ZIP Переданный формат ZIP-файла не соответствует стандарту либо испорчен.
ZIP_ERROR_NAME_ALREADY_EXITS Имя, под которым пользователь пытается сохранить файл, уже используется в архиве.
ZIP_ERROR_BAD_URL Переданная ссылка не ссылается на ZIP-архив, либо доступ к указанному интернет-ресурсу запрещен настройками терминала.

При получении пользовательской ошибки необходимо явно привести ее к перечислению ENUM_ZIP_ERROR и обработать соответствующим образом. Пример работы с ошибками, возникающими в ходе работы с классами архивирования, представлен ниже в виде скрипта:

4.5. Описание файлов, приложенных к статье

Ниже приведено краткое описание файлов, приложенных к статье:

  • Zip\Zip.mqh — содержит основной класс для работы с архивами CZip.
  • Zip\ZipContent.mqh — содержит базовый класс CZipContent для основных классов элементов архива: CZipFile и CZipDirectory.
  • Zip\ZipFile.mqh — содержит класс для работы с ZIP-файлами архива.
  • Zip\ZipDirectory.mqh — содержит класс для работы с ZIP-папками архива.
  • Zip\ZipHeader.mqh — в файле даны описания структур File Local Header, Central Directory и End Central Directory Record.
  • Zip\ZipDefines.mqh — перечислены определения, константы и коды ошибок, используемые при работе с классами по архивированию.
  • Dictionary.mqh — вспомогательный класс, обеспечивающий контроль уникальности имен файлов и директорий, добавляемых в архив. Алгоритм работы этого класса подробно описан в статье «Рецепты MQL5 — Реализуем ассоциативный массив или словарь для быстрого доступа к данным».

Все файлы, приведенные в статье, необходимо разместить относительно внутреннего каталога \MQL5\Include. Для начала работы с классом в проект необходимо включить файл Zip\Zip.mqh. Опишем в качестве примера скрипт, создающий ZIP-архив и записывающий в него текстовый файл с сообщением «test»:

После его выполнения на жестком диске компьютера в центральном каталоге файлов для MetaTrader 5 появится новый ZIP-архив с именем Test.zip, содержащий один текстовой файл с надписью «test».

Архив, прилагаемый к данной статье, создан с помощью MQL-архиватора CZip, который здесь описан.

Заключение

Мы подробно рассмотрели структуру ZIP-архива и создали классы, реализующие работу с этим типом архивов. Этот формат архивирования был разработан еще в конце 80-ых годов прошлого века, но это не мешает ему оставаться самым популярным форматом сжатия данных. Набор данных классов может оказать разработчику торговых систем неоценимую пользу. С его помощью можно экономно хранить собираемые данные, будь то тиковая история или другая торговая информация. Часто различная аналитическая информация также предоставляется в сжатом виде. В этом случае умение работать с такой информацией даже в сжатом виде также может оказаться полезным.

Описываемые классы скрывают многие технические аспекты работы с архивами, предоставляя на пользовательском уровне простые и понятные методы работы с ними, сходные с теми операциями, что привыкли совершать пользователи с программами архивирования: добавление и извлечение файлов из архива, создание новых и загрузка уже существующих архивов, в том числе размещенных на удаленных сторонних серверах. Эти возможности полностью решают большинство задач, связанных с архивированием, и делают программирование в среде MetaTrader еще проще и функциональнее.

Распаковка Zip

Ребят, помогите доработать код. Распаковывает зип на отлично, только мне нужно, чтобы он еще и распаковывал файлы в папку с таким именем как и имя архива.

15.06.2020, 22:23

Распаковка кода GitHub
Здравствуйте! Совсем недавно начала заниматься программированием на Java для Android. Тремя.

Распаковка ресурсов из пакета на устройство
Добрый день. Можно ли создать апк файл при запуске которого будет извлекать из себя файлы по.

Распаковка JSON-данных, полученных в get-запросе VK api
Пишу в Android Studio программку, начал с простого, чтобы понять, как всё работает. Вот код: .

Отправка Zip файла по email
Здравствуйте! Стоит задача отправить архив, который находится внутри приложения по email. Как мне.

Открыть zip архив и распаковать pdf файл с паролем
из zip архива распаковать pdf файл с паролем

Илон Маск рекомендует:  sha1 - Возвращает SHA1 хэш строки
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL