Что такое код zip_entry_filesize

Содержание

Linux.yaroslavl.ru

Учебник РНР
Назад Вперёд

zip_entry_filesize — запрашивает Actual File Size для Directory Entry.

Описание

int zip_entry_filesize (resource zip_entry)

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

Zip File. Extract ToDirectory Метод

Определение

Извлекает все файлы в указанном ZIP-архиве в каталогу в файловой системе. Extracts all the files in the specified zip archive to a directory on the file system.

Перегрузки

Извлекает все файлы в указанном ZIP-архиве в каталогу в файловой системе. Extracts all the files in the specified zip archive to a directory on the file system.

Извлекает все файлы в указанном архиве в каталоге в файловой системе. Extracts all of the files in the specified archive to a directory on the file system.

Извлекает все файлы в указанном ZIP-архиве к каталог в файловой системе и использует указанную кодировку для имен записей. Extracts all the files in the specified zip archive to a directory on the file system and uses the specified character encoding for entry names.

Извлекает все файлы в указанном архиве в каталоге в файловой системе. Extracts all of the files in the specified archive to a directory on the file system.

ExtractToDirectory(String, String)

Извлекает все файлы в указанном ZIP-архиве в каталогу в файловой системе. Extracts all the files in the specified zip archive to a directory on the file system.

Параметры

Путь к архиву, который требуется извлечь. The path to the archive that is to be extracted.

Путь к каталогу, в котором следует поместить извлеченные файлы, заданный как относительный или абсолютный путь. The path to the directory in which to place the extracted files, specified as a relative or absolute path. Относительный путь интерпретируется относительно текущего рабочего каталога. A relative path is interpreted as relative to the current working directory.

Исключения

Параметр destinationDirectoryName или sourceArchiveFileName является Empty, содержит только пробелы или хотя бы один недопустимый символ. destinationDirectoryName or sourceArchiveFileName is Empty, contains only white space, or contains at least one invalid character.

Параметр destinationDirectoryName или sourceArchiveFileName имеет значение null . destinationDirectoryName or sourceArchiveFileName is null .

Указанная длина пути в destinationDirectoryName или sourceArchiveFileName превышает максимальную длину, определенную в системе. The specified path in destinationDirectoryName or sourceArchiveFileName exceeds the system-defined maximum length.

Указанный путь недопустим (например, он соответствует неподключенному диску). The specified path is invalid (for example, it is on an unmapped drive).

Каталог, заданный параметром destinationDirectoryName , уже существует. The directory specified by destinationDirectoryName already exists.

-или- -or- Имя записи в архиве имеет значение Empty, содержит только пробелы или содержит по крайней мере один недопустимый символ. The name of an entry in the archive is Empty, contains only white space, or contains at least one invalid character.

— или — -or- Извлечение записи архива создаст файл, который находится вне каталога, заданного destinationDirectoryName . Extracting an archive entry would create a file that is outs >destinationDirectoryName . (Например, это может произойти, если имя записи содержит методы доступа родительского каталога.) (For example, this might happen if the entry name contains parent directory accessors.) -или- -or- Запись архива, которую требуется извлечь, имеет то же имя, что и запись, которая уже была извлекается из того же архива. An archive entry to extract has the same name as an entry that has already been extracted from the same archive.

Вызывающий код не имеет необходимого разрешения на доступ к архиву или целевому каталогу. The caller does not have the required permission to access the archive or the destination directory.

destinationDirectoryName или sourceArchiveFileName содержит недопустимый формат. destinationDirectoryName or sourceArchiveFileName contains an invalid format.

Не удалось найти sourceArchiveFileName . sourceArchiveFileName was not found.

Архив, заданный параметром sourceArchiveFileName , не является допустимым ZIP-архивом. The archive specified by sourceArchiveFileName is not a valid zip archive.

-или- -or- Не удалось найти запись архива или она была повреждена. An archive entry was not found or was corrupt.

— или — -or- Запись архива была сжата с помощью неподдерживаемого метода сжатия. An archive entry was compressed by using a compression method that is not supported.

Примеры

В этом примере показано, как создать и извлечь ZIP-архив с помощью ZipFile класса. This example shows how to create and extract a zip archive by using the ZipFile class. Она сжимает содержимое папки в ZIP-архив и извлекает это содержимое в новую папку. It compresses the contents of a folder into a zip archive and extracts that content to a new folder. Чтобы использовать класс ZipFile, укажите в проекте ссылку на сборку System.IO.Compression.FileSystem . To use the ZipFile class, you must reference the System.IO.Compression.FileSystem assembly in your project.

Комментарии

Этот метод создает указанный каталог и все подкаталоги. This method creates the specified directory and all subdirectories. Каталог назначения не может уже существовать. The destination directory cannot already exist. Исключения, связанные с проверкой путей в destinationDirectoryName параметрах или sourceArchiveFileName , вызываются перед извлечением. Exceptions related to validating the paths in the destinationDirectoryName or sourceArchiveFileName parameters are thrown before extraction. В противном случае, если во время извлечения возникает ошибка, архив остается частично извлеченным. Otherwise, if an error occurs during extraction, the archive remains partially extracted. Каждый извлеченный файл имеет тот же относительный путь к каталогу, destinationDirectoryName который указан в качестве исходной записи в корневую папку архива. Each extracted file has the same relative path to the directory specified by destinationDirectoryName as its source entry has to the root of the archive.

ExtractToDirectory(String, String, Boolean)

Извлекает все файлы в указанном архиве в каталоге в файловой системе. Extracts all of the files in the specified archive to a directory on the file system.

Параметры

Путь в файловой системе к архиву, который требуется извлечь. The path on the file system to the archive that is to be extracted.

Путь к целевому каталогу в файловой системе. The path to the destination directory on the file system. Указанный каталог не должен существовать, но каталог, в котором он находится, должен существовать. The directory specified must not exist, but the directory that it is contained in must exist.

Значение true для перезаписи файлов; в противном случае — значение false . true to overwrite files; false otherwise.

Исключения

sourceArchiveFileName или destinationDirectoryName представляет собой строку нулевой длины, содержащую только пробелы или один или несколько недопустимых символов, заданных методом InvalidPathChars. sourceArchiveFileName or destinationDirectoryName is a zero-length string, contains only whitespace, or contains one or more invalid characters as defined by InvalidPathChars.

Параметр sourceArchiveFileName или destinationDirectoryName имеет значение null . sourceArchiveFileName or destinationDirectoryName is null .

sourceArchiveFileName или destinationDirectoryName указывает путь, имя файла или оба параметра, которые превышают установленное в системе максимальное значение. sourceArchiveFileName or destinationDirectoryName specifies a path, a file name, or both that exceed the system-defined maximum length.

Путь, указанный sourceArchiveFileName или destinationDirectoryName , является недопустимым (например, он ведет на несопоставленный диск). The path specified by sourceArchiveFileName or destinationDirectoryName is invalid (for example, it is on an unmapped drive).

Каталог, заданный параметром destinationDirectoryName , уже существует. The directory specified by destinationDirectoryName already exists.

Произошла ошибка ввода-вывода. An I/O error has occurred.

Имя ZipArchiveEntry имеет нулевую длину, содержит только пробелы или один или несколько недопустимых символов, заданных методом InvalidPathChars. The name of a ZipArchiveEntry is zero-length, contains only whitespace, or contains one or more invalid characters as defined by InvalidPathChars.

Извлечение ZipArchiveEntry может привести к назначению файла, находящегося за пределами целевого каталога (например, из-за наличия методов доступа к родительскому каталогу). Extracting a ZipArchiveEntry would result in a file destination that is outside the destination directory (for example, because of parent directory accessors).

ZipArchiveEntry имеет то же имя, что и уже извлеченная запись из того же архива. A ZipArchiveEntry has the same name as an already extracted entry from the same archive.

У вызывающего объекта отсутствует необходимое разрешение. The caller does not have the required permission.

Параметр sourceArchiveFileName или destinationDirectoryName имеет недопустимый формат. sourceArchiveFileName or destinationDirectoryName is in an invalid format.

Не удалось найти sourceArchiveFileName . sourceArchiveFileName was not found.

Архив, заданный параметром sourceArchiveFileName , не является допустимым ZipArchive. The archive specified by sourceArchiveFileName is not a valid ZipArchive.

ZipArchiveEntry поврежден или не может быть найден. A ZipArchiveEntry was not found or was corrupt.

ZipArchiveEntry сжат с помощью неподдерживаемого метода сжатия. A ZipArchiveEntry has been compressed using a compression method that is not supported.

Комментарии

Указанный каталог не должен существовать. The specified directory must not exist. Метод создает указанный каталог и все подкаталоги. The method creates the specified directory and all subdirectories.

Если при извлечении архива возникла ошибка, архив будет извлечен частично. If there is an error while extracting the archive, the archive will remain partially extracted.

Каждая запись будет извлечена таким образом, что извлеченный файл имеет тот же относительный путь к тому destinationDirectoryName , что и запись в архив. Each entry will be extracted such that the extracted file has the same relative path to the destinationDirectoryName as the entry has to the archive.

Путь может указывать сведения относительного или абсолютного пути. The path can specify relative or absolute path information. Относительный путь интерпретируется относительно текущего рабочего каталога. A relative path is interpreted as relative to the current working directory.

Если файл для архивации имеет неверное время последнего изменения, то будет использоваться первая дата и время, представленные в формате метки времени ZIP (полночь 1 января 1980). If a file to be archived has an invalid last modified time, the first date and time representable in the Zip timestamp format (midnight on January 1, 1980) will be used.

ExtractToDirectory(String, String, Encoding)

Извлекает все файлы в указанном ZIP-архиве к каталог в файловой системе и использует указанную кодировку для имен записей. Extracts all the files in the specified zip archive to a directory on the file system and uses the specified character encoding for entry names.

Параметры

Путь к архиву, который требуется извлечь. The path to the archive that is to be extracted.

Путь к каталогу, в котором следует поместить извлеченные файлы, заданный как относительный или абсолютный путь. The path to the directory in which to place the extracted files, specified as a relative or absolute path. Относительный путь интерпретируется относительно текущего рабочего каталога. A relative path is interpreted as relative to the current working directory.

Кодирование, используемое при чтении или записи имен записей в этом архиве. The encoding to use when reading or writing entry names in this archive. Задайте значение для этого параметра, только если кодирование требуется для взаимодействия с инструментами и библиотеками ZIP-архива, которые не поддерживают кодирование UTF-8 для имен записей. Specify a value for this parameter only when an encoding is required for interoperability with zip archive tools and libraries that do not support UTF-8 encoding for entry names.

Исключения

Параметр destinationDirectoryName или sourceArchiveFileName является Empty, содержит только пробелы или хотя бы один недопустимый символ. destinationDirectoryName or sourceArchiveFileName is Empty, contains only white space, or contains at least one invalid character.

-или- -or- entryNameEncoding установлено на кодировку Юникода, отличное от UTF-8. entryNameEncoding is set to a Unicode encoding other than UTF-8.

Значение параметра destinationDirectoryName или sourceArchiveFileName — null . destinationDirectoryName or sourceArchiveFileName is null .

Указанная длина пути в destinationDirectoryName или sourceArchiveFileName превышает максимальную длину, определенную в системе. The specified path in destinationDirectoryName or sourceArchiveFileName exceeds the system-defined maximum length.

Указанный путь недопустим (например, он соответствует неподключенному диску). The specified path is invalid (for example, it is on an unmapped drive).

Каталог, заданный параметром destinationDirectoryName , уже существует. The directory specified by destinationDirectoryName already exists.

— или — -or- Имя записи в архиве имеет значение Empty, содержит только пробелы или содержит по крайней мере один недопустимый символ. The name of an entry in the archive is Empty, contains only white space, or contains at least one invalid character.

— или — -or- Извлечение записи архива создаст файл, который находится вне каталога, заданного destinationDirectoryName . Extracting an archive entry would create a file that is outs >destinationDirectoryName . (Например, это может произойти, если имя записи содержит методы доступа родительского каталога.) (For example, this might happen if the entry name contains parent directory accessors.) — или — -or- Запись архива, которую требуется извлечь, имеет то же имя, что и запись, которая уже была извлекается из того же архива. An archive entry to extract has the same name as an entry that has already been extracted from the same archive.

Вызывающий код не имеет необходимого разрешения на доступ к архиву или целевому каталогу. The caller does not have the required permission to access the archive or the destination directory.

destinationDirectoryName или sourceArchiveFileName содержит недопустимый формат. destinationDirectoryName or sourceArchiveFileName contains an invalid format.

Не удалось найти sourceArchiveFileName . sourceArchiveFileName was not found.

Архив, заданный параметром sourceArchiveFileName , не является допустимым ZIP-архивом. The archive specified by sourceArchiveFileName is not a valid zip archive.

— или — -or- Не удалось найти запись архива или она была повреждена. An archive entry was not found or was corrupt.

-или- -or- Запись архива была сжата с помощью неподдерживаемого метода сжатия. An archive entry was compressed by using a compression method that is not supported.

Комментарии

Этот метод создает указанный каталог и все подкаталоги. This method creates the specified directory and all subdirectories. Каталог назначения не может уже существовать. The destination directory cannot already exist. Исключения, связанные с проверкой путей в destinationDirectoryName параметрах или sourceArchiveFileName , вызываются перед извлечением. Exceptions related to validating the paths in the destinationDirectoryName or sourceArchiveFileName parameters are thrown before extraction. В противном случае, если во время извлечения возникает ошибка, архив остается частично извлеченным. Otherwise, if an error occurs during extraction, the archive remains partially extracted. Каждый извлеченный файл имеет тот же относительный путь к каталогу, destinationDirectoryName который указан в качестве исходной записи в корневую папку архива. Each extracted file has the same relative path to the directory specified by destinationDirectoryName as its source entry has to the root of the archive.

Если entryNameEncoding для параметра задано значение, отличное null от, имена записей декодированы в соответствии со следующими правилами. If entryNameEncoding is set to a value other than null , entry names are decoded according to the following rules:

Для имен записей, в которых не задан флаг кодировки языка (в битовом флаге общего назначения локального заголовка файла), имена записей декодированы с использованием указанной кодировки. For entry names where the language encoding flag (in the general-purpose bit flag of the local file header) is not set, the entry names are decoded by using the specified encoding.

Для записей, в которых установлен флаг кодировки языка, имена записей декодированы с помощью UTF-8. For entries where the language encoding flag is set, the entry names are decoded by using UTF-8.

Если entryNameEncoding параметр имеет null значение, имена записей декодированы в соответствии со следующими правилами. If entryNameEncoding is set to null , entry names are decoded according to the following rules:

Для записей, в которых не задан флаг кодировки языка (в битовом флаге общего назначения локального заголовка файла), имена записей декодированы с использованием текущей системной кодовой страницы по умолчанию. For entries where the language encoding flag (in the general-purpose bit flag of the local file header) is not set, entry names are decoded by using the current system default code page.

Для записей, в которых установлен флаг кодировки языка, имена записей декодированы с помощью UTF-8. For entries where the language encoding flag is set, the entry names are decoded by using UTF-8.

ExtractToDirectory(String, String, Encoding, Boolean)

Извлекает все файлы в указанном архиве в каталоге в файловой системе. Extracts all of the files in the specified archive to a directory on the file system.

Параметры

Путь в файловой системе к архиву, который требуется извлечь. The path on the file system to the archive that is to be extracted.

Путь к целевому каталогу в файловой системе. The path to the destination directory on the file system. Указанный каталог не должен существовать, но каталог, в котором он находится, должен существовать. The directory specified must not exist, but the directory that it is contained in must exist.

Кодирование, используемое при чтении имен записей в этом ZipArchive. The encoding to use when reading entry names in this ZipArchive.

Значение true для перезаписи файлов; в противном случае — значение false . true to overwrite files; false otherwise.

Исключения

sourceArchiveFileName или destinationDirectoryName представляет собой строку нулевой длины, содержащую только пробелы или один или несколько недопустимых символов, заданных методом InvalidPathChars. sourceArchiveFileName or destinationDirectoryName is a zero-length string, contains only whitespace, or contains one or more invalid characters as defined by InvalidPathChars.

— или — -or- entryNameEncoding установлено на кодировку Юникода, отличное от UTF-8. entryNameEncoding is set to a Unicode encoding other than UTF-8.

Параметр sourceArchiveFileName или destinationDirectoryName имеет значение null . sourceArchiveFileName or destinationDirectoryName is null .

sourceArchiveFileName или destinationDirectoryName указывает путь, имя файла или оба параметра, которые превышают установленное в системе максимальное значение. sourceArchiveFileName or destinationDirectoryName specifies a path, a file name, or both that exceed the system-defined maximum length.

Путь, указанный sourceArchiveFileName или destinationDirectoryName , является недопустимым (например, он ведет на несопоставленный диск). The path specified by sourceArchiveFileName or destinationDirectoryName is invalid (for example, it is on an unmapped drive).

Каталог, заданный параметром destinationDirectoryName , уже существует. The directory specified by destinationDirectoryName already exists.

Произошла ошибка ввода-вывода. An I/O error has occurred.

Имя ZipArchiveEntry имеет нулевую длину, содержит только пробелы или один или несколько недопустимых символов, заданных методом InvalidPathChars. The name of a ZipArchiveEntry is zero-length, contains only whitespace, or contains one or more invalid characters as defined by InvalidPathChars.

Извлечение ZipArchiveEntry может привести к назначению файла, находящегося за пределами целевого каталога (например, из-за наличия методов доступа к родительскому каталогу). Extracting a ZipArchiveEntry would result in a file destination that is outside the destination directory (for example, because of parent directory accessors).

ZipArchiveEntry имеет то же имя, что и уже извлеченная запись из того же архива. A ZipArchiveEntry has the same name as an already extracted entry from the same archive.

У вызывающего объекта отсутствует необходимое разрешение. The caller does not have the required permission.

Параметр sourceArchiveFileName или destinationDirectoryName имеет недопустимый формат. sourceArchiveFileName or destinationDirectoryName is in an invalid format.

Не удалось найти sourceArchiveFileName . sourceArchiveFileName was not found.

Архив, заданный параметром sourceArchiveFileName , не является допустимым ZipArchive. The archive specified by sourceArchiveFileName is not a valid ZipArchive.

Не удалось найти запись архива или она была повреждена. An archive entry was not found or was corrupt.

Запись архива была сжата с использованием неподдерживаемого метода сжатия. An archive entry has been compressed using a compression method that is not supported.

Комментарии

Указанный каталог не должен существовать. The specified directory must not exist. Этот метод создаст указанный каталог и все подкаталоги. This method will create the specified directory and all subdirectories.

Если при извлечении архива возникла ошибка, архив будет извлечен частично. If there is an error while extracting the archive, the archive will remain partially extracted.

Каждая запись будет извлечена таким образом, что извлеченный файл имеет тот же относительный путь к тому destinationDirectoryName , что и запись в архив. Each entry will be extracted such that the extracted file has the same relative path to the destinationDirectoryName as the entry has to the archive.

Путь может указывать сведения относительного или абсолютного пути. The path can specify relative or absolute path information. Относительный путь интерпретируется относительно текущего рабочего каталога. A relative path is interpreted as relative to the current working directory.

Если файл для архивации имеет неверное время последнего изменения, то будет использоваться первая дата и время, представленные в формате метки времени ZIP (полночь 1 января 1980). If a file to be archived has an invalid last modified time, the first date and time representable in the Zip timestamp format (midnight on January 1, 1980) will be used.

PHP | zip_entry_filesize() Function

The zip_entry_filesize() function is an inbuilt function in PHP which is used to return the original file size of a zip archive entry before compression. The zip entry resource is to be read and sent as a parameter to the zip_entry_filesize() function and it returns the value in bytes on Success.

Syntax:

Parameters: This function accepts single parameter $zip_entry which is mandatory. It is a parameter which specify the zip entry resource.

Return Value: It returns the value in bytes on Success.

Errors And Exceptions:

  • The zip_entry_filesize() returns the size in bytes of a file before compression only on Success otherwise it returns a PHP warning.
  • The zip_entry_filesize() function returns an ER_OPEN error if the zip archive is invalid.
  • The zip_entry_filesize() function returns an ER_NOZIP error if the zip archive is empty.

Below programs illustrate the zip_entry_filesize() function in PHP:
Program 1:

Работаем с 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 еще проще и функциональнее.

Как с помощью ZipArchive распаковать данные содержащиеся в переменной php?

Это пример если создавать ещё один файл, через fopen, но мне так не подходит

попробуйте вот так :

но могут быть нюансы

Vladimir L,
переменная $text с содержимым?
попробуйте так :

Warning: ZipArchive::close(): Can’t remove file: No such file or directory in /var/www/docs/lobochkin.ru/test/conv.php on line 9
1

Хочу так попробовать
но не хочет работать, а если записать так то работает

Библиотека примеров приложений Java

Оглавление
Выбор файлов
Простейший редактор текста
Копирование файлов UNICODE
Сохранение объекта Java в файле
Произвольные классы и файлы
Буферизация потоков
Разбор конфигура-
ционного файла

Работа с консолью
Работа с классом PrintWriter
Разбор строк класса String
Загрузка и просмотр изображений
Потоки в оперативной памяти
Конвейерные потоки
Комбинирование двух потоков
Комбинирование нескольких потоков
Поиск слова в текстовом файле
Произвольный доступ к файлу
Информация о файле
Работа с каталогами
Просмотр содержимого каталога
Просмотр каталога с фильтром
Панель для выбора каталога
Список системных свойств
Сохранение списка системных свойств
Контрольная сумма файла
Копирование, переименование, удаление файлов
Архивы ZIP
Создание архива ZIP
Распаковка архива ZIP
Обход дерева каталогов

7.27. Работа с архивами формата ZIP

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

Немного теории

Среди различных библиотек классов Java есть одна очень интересная — с названием java.util.zip. Она позволяет работать с библиотеками файлов широко распространенных форматов ZIP и GZIP.

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

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

Чтобы получить доступ к таким файлам, вы должны прежде всего создать объект класса ZipFile, пользуясь одним из конструкторов этого класса. Первый конструктор позволяет открыть ZIP-файл через объект класса File, а второй — через полный путь к имени файла:

В процессе создания объекта класса ZipFile могут возникать как обычные для файлов исключения IOException, так и исключения класса ZipException, специфические для класса ZipFile.

Класс ZipFile

В классе ZipFile определены несколько методов:

Метод Описание
entries Возвращает перечисление объектов, хранящихся в архивной библиотеке формата ZIP
getName Возвращает имя ZIP-файла
getInputStream Возвращает ссылку на входной поток для чтения объектов их архива
getEntry Возвращает объект, хранящийся в библиотеке, по его имени
close Закрывает ZIP-файл

Методы entries и getEntry позволяют получить элементы, хранящиеся в архиве, как объекты класса ZipEntry. Ниже мы получаем перечисление таких объектов:

Чтобы извлечь элементы перечисления и записать их в массив zipEntries класса Vector, мы можем создать цикл:

Класс ZipEntry

В классе ZipEntry определены две константы, конструктор и несколько методов.

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

Если файл сохранен в архиве без компрессии, для него используется метод ZipEntry.STORED, а если с компрессией — метод ZipEntry.DEFLATED.

Конструктор класса ZipEntry позволяет создать новый элемент оглавления архива с заданным именем:

Что же касается методов класса ZipEntry, то их можно разделить на две группы, одна из которых предназначена для установки атрибутов элемента оглавления архива ZIP, а другая — для извлечения.

Рассмотрим эти методы.

setCrc

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

getCrc

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

setMethod

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

getMethod

Метод getMethod позволяет знать способ компрессии, который был использован для файла, соответствующего данному элементу архива. Он может возвращать значения ZipEntry.DEFLATED или ZipEntry.STORED.

setExtra

С помощью этого метода можно записать в элемент оглавления архива произвольную дополнительную информацию.

getExtra

Метод getExtra возвращает дополнительную информацию, записанную в элементе оглавления архива.

setComment

Запись в элемент оглавления архива дополнительной текстовой строки комментария.

getComment

Чтение строки комментария.

getCompressedSize

Метод getCompressedSize возвращает размер сжатого файла или значение -1, если этот размер неизвестен.

isDirectory

Помимо файлов, в архиве могут хранится каталоги. В этом случае имя соответствующего элемента должно оканчиваться символом «/». Метод isDirectory позволяет узнать, является ли данные элемент описателем каталога или файла. В первом случае он возвращает значение true, а во втором — false.

getName

Этот метод позволяет узнать имя, соответствующее данному элементу оглавления архива. Изменить имя нельзя — оно передается конструктору класса ZipEntry при создании нового элемента оглавления.

setTime

Установка времени модификации файла (в количестве миллисекунд, прошедших с начала эпохи).

getTime

Определение времени модификации файла.

setSize

Установка размера несжатого файла.

getSize

Определение размера несжатого файла.

Описание примера

Наш пример автономного приложения ZipFileView создает одно главное окно класса Frame, в котором предусмотрено меню (рис. 1).

Рис. 1. Главное окно приложения

Строка Open меню File позволяет выбрать (с помощью стандартной диалоговой панели класса FileDialog) файл формата ZIP. Сразу после выбора такого файла на экране появляется диалоговая панель со списком имен элементов оглавления выбранного архива ZIP (рис. 2).

Рис. 2. Список элементов оглавления выбранного архива

Если выделить в этом списке любую строку, в главном окне приложения появится описание содержимого соответствующего элемента оглавления (рис. 1).

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

Рассмотрим наиболее интересные фрагменты исходного текста приложения.

Прежде всего обратите внимание на классы, подключаемые оператором import:

Классы java.util.zip.* нужны для работы с файлами ZIP, а класс java.text.* — для форматирования строки даты изменения файлов, записанных в архиве.

Когда пользователь выбирает строку Open из меню File, метод actionPerformed, определенный в классе FrameWindow, отображает на экране стандартную диалоговую панель для выбора ZIP-файла:

Путь к выбранному файлу записывается в переменную szPath. Он затем передается конструктору класса ZipFileDialog, определенному в нашем приложении для отображения списка элементов оглавления ZIP-файла:

Класс ZipFileDialog

Класс ZipFileDialog создан на базе класса Dialog и реализует ряд интерфейсов:

В этом классе определено несколько полей.

В поле zf класса ZipFile хранится ссылка на объект, созданная для выбранного пользователем ZIP-файла:

Массив zipEntries класса Vector предназначен для хранения извлеченных элементов оглавления ZIP-файла:

Конструктор класса ZipFileDialog создает все необходимые компоненты и добавляют их в окно панели с применением режима размещения компонент GridBagLayout. Перед завершением своей работы он вызывает метод updateList:

Этот метод заполняет список, расположенный в окне панели, именами элементов оглавления архива.

Метод updateList класса ZipFileDialog

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

Первым делом этот метод очищает список, удаляя из него все элементы:

Далее метод updateList выполняет все операции в блоке try-catch, что необходимо для обработки исключений.

Первым делом мы создаем объект класса ZipFile и с помощью метода entries получаем перечисление элементов оглавления архива:

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

Пользуясь полученным перечислением мы заполняем массив zipEntries, записывая в него объекты класса ZipEntry:

Далее перебирая элементы массива zipEntries в цикле мы извлекаем имена элементов и добавляем их в список, расположенный в окне диалоговой панели:

Метод itemStateChanged класса ZipFileDialog

Когда пользователь выделяет в списке строку имени элемента оглавления массива, управление передается методу itemStateChanged, реализованному как часть интерфейса ItemListener:

Наша реализация этого метода вызывает метод getZipFileEntryInfo, извлекающий информацию из элемента оглавления архива и отображающий ее в главном окне приложения.

Метод getZipFileEntryInfo класса ZipFileDialog

Получив управление, метод getZipFileEntryInfo определяет номер элемента, выделенного пользователем в списке:

Далее из массива zipEntries извлекается соответствующий элемент класса ZipEntry:

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

Затем мы формируем новый текст в переменной szItemInfo, записывая туда значения атрибутов, извлеченные из элемента оглавления соответствующими методами класса ZipEntry:

Затем полученная строка добавляется в редактор главного окна приложения:

Метод actionPerformed класса ZipFileDialog

Когда пользователь нажимает кнопку Extract, расположенную в нижней части диалоговой панели со списком, метод actionPerformed извлекает из списка имя выделенного элемента архива и передает его методу saveZipFile:

Метод saveZipFile класса ZipFileDialog

В задачу метода saveZipFile входит извлечение из архива указанного файла и сохранение его на диске.

Прежде всего мы выделяем из полного пути к файлу имя:

Это имя затем используется при инициализации панели выбора выходного класса:

Таким образом, пользователю предлагается сохранить файл под тем именем, под которым он хранился в архиве.

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

На следующем этапе метод создает выходной поток, связанный с файлом:

Узнав номер строки, выделенной пользователем в списке имен файлов, мы извлекаем из массива zipEntries соответствующий элемент оглавления класса ZipEntry:

Далее нам необходимо скопировать данные из архива в выходной файл fos.

Чтобы это сделать, мы получаем ссылку на входной поток, связанный с объектом ZipFile:

Копирование выполняется в цикле с применением методов read и write:

zip_entry_filesize

(PHP 4 >= 4.1.0, PHP 5 >= 5.2.0, PHP 7, PECL zip >= 1.0.0)

zip_entry_filesize — Retrieve the actual file size of a directory entry

Description

Returns the actual size of the specified directory entry.

Parameters

A directory entry returned by zip_read() .

Return Values

The size of the directory entry.

See Also

  • zip_open() — Open a ZIP file archive
  • zip_read() — Read next entry in a ZIP file archive

User Contributed Notes

Simple function that return total size of files in archive.
May be useful for check for zip bombs.

function get_zip_originalsize ( $filename ) <
$size = 0 ;
$resource = zip_open ( $filename );
while ( $dir_resource = zip_read ( $resource )) <
$size += zip_entry_filesize ( $dir_resource );
>
zip_close ( $resource );

как создать Java почтовый архив с ограничением размера файла не более

Мне нужно написать алгоритм, в Java (для андроид приложение), чтобы прочитать папку, содержащую несколько папок, и каждый из них, содержащих изображений и аудио файлов, так что структура такова: mainDir/categorySubfolder/myFile1.jpg

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

Я попробовал несколько примеров из сети, и я прочитал документацию Java, но я не могу управлять, чтобы понять и поставить все это вместе, как мне нужно это. Кто-то делал это раньше или имеет ссылку или пример для меня?

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

Я открыт для предложений или лучше работающий пример.

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

Вы можете найти больше примеров на их веб-сайте.

Я использую ниже кода / класса, чтобы разделить и пронестись большое количество / размер файлов. Я испытал этот класс на ниже

  • количество несжатых файлов: 116
  • Общий размер (несжатый): 29,1 ГБ
  • Ограничение ZIP размер файла (каждый): 3 ГБ [MAX_ZIP_SIZE]
  • Общий размер (сжатый): 7,85 ГБ
  • количество ZIP — файл (расщепляются в MAX_ZIP_SIZE ): 3

вы должны изменить значение MAX_ZIP_SIZE 16 (MB) * 1024 * 1024 = 16777216-22 (почтовый размер заголовка) = 16777194 .
В моем коде, MAX_ZIP_SIZE установлено 3 ГБ ( ZIP имеет ограничение 4 Гб на различных вещах ).

Окончательный долго MAX_ZIP_SIZE = 3221225472L; // 3 ГБ

Я вернул все Exception сообщения в виде строки для работы с ним. это мое дело связано с проектом.

Насколько я могу видеть , как разделить огромный почтовый файл на несколько томов? просто предлагает отслеживать размер архива до сих пор, и , когда она приближается к некоторому произвольному значению (которое должно быть ниже , чем ваш максимум), то решит начать новый файл. Таким образом , для предела 16MB, вы можете установить значение 10MB и начать новый почтовый индекс всякий раз , когда это будет достигнуто, но если вы достигнете 9MB и ваш следующий файл молнии до 8MB, вы в конечном итоге с почтовым индексом больше , чем ваш предел.

Код, указанный на этом посту, похоже, не работает для меня, потому что 1) он получил размер до ZipEntry был создан, поэтому он всегда был 0 и 2) он не выписывать любой почтовый :-) Если я получил, что неправильно — дайте мне знать.

Следующие работы для меня. Для простоты, я взял его из обертки и просто все это в основных (String арге []). Есть много, много способов этот код можно было бы улучшить :-)

Работа с архивами 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).

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

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 — такой вопрос периодически задают джуниорам на собеседовании.

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

Илон Маск рекомендует:  Что такое код domnode &#62;insert_before
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL