Тема: JScript: Работа с ZIP-архивами: расширенная версия
Как уже сказано в сообщении #5 темы JScript: работа с ZIP архивами предыдущая работа доступна но только в архиве "Разработки". В настоящей теме предлагаю рассмотреть, обсудить и покритиковать новую версию класса для работы с ZIP-архивами.
Предыдущая версия успешно справлялась с задачей архивирования. Не более. Недавно я вернулся к ней и обнаружил, что иногда решение не работает - файлы не помещаются в архив. Была найдена причина - необходимо указывать полный путь до архивируемого файла. Сейчас код существенно переработан и позволяет выполнять многие действия с архивами ранее недоступные в предыдущей версии.
Вначале будет дано краткое описание API, показаны примеры использования, затем приведен исходный код и ссылка на актуальную версию библиотеки. Критика, замечания и багрепорты приветствуются.
***
API библиотеки
Конструктор
ZipFile(name, create, overwrite)
Конструктор, создает новый объект для работы с архивами. Фактически вызывает метод ZipFile#open, который выполняет все необходимые действияСвойства
ZipFile#name
Полный путь до архивного файлаZipFile#file
Объект Folder, виртуальная папка проводника, реализующая доступ к архивуМетоды
ZipFile#open(name, create, overwrite)
Открывает архивный файл. Если аргумент create == true, то создается новый файл. Прежнее значение будет перезаписано, если указан аргумент overwrite == true. Инициализирует два свойства:ZipFile#flush(timeout)
Сброс данных в архив. Метод-подделка необходима для создания задержки в timeout миллисекунд, чтобы предотвратить завершение скрипта раньше завершения создания архива.ZipFile#forInput(input, func)
Метод используется для помещения объектов из массива input в архив. Для этого вторым аргументом передается функция, которая будет вызвана для каждого элемента массива. Функция использует два аргумента
1. объект File или Folder, который будет помещен в архив
2. объект Folder, виртуальная папка проводника, реализующая доступ к архивуZipFile#forEach(func)
Метод используется для работы с объектами внутри архива. Для работы с объектами методу передается функция, которая вызывается для каждого объекта в архиве. Функция использует два аргумента
1. объект File или Folder в архиве
2. объект Folder, виртуальная папка проводника, реализующая доступ к архиву
***
Пример 1. Создание ZIP-архива
var filename = 'test.zip';
var create = true;
var overwrite = true;
WScript.Echo('*** Create the file');
var zipfile = new ZipFile();
zipfile.open(filename, create, overwrite);
WScript.Echo('*** Put objects to the archive');
zipfile.forInput(
[
'C:\\Logs',
'C:\\tmp',
],
function(folderItem, arcfile)
{
WScript.Echo(folderItem.Path);
arcfile.CopyHere(folderItem.Path, 0);
WScript.Sleep(3000);
}
);В этом примере создается архивный файл test.zip, в который будут помещены существующие каталоги C:\Log и C:\tmp. Существовавший до этого файл test.zip будет перезаписан.
Было замечено, что при увеличении размера архивного файла или архивировании большого количества файлов требуется некоторое время перед помещением следующего элемента. Поэтому используется задержка в 3 секунды после копирования файлов в архив.
Для копирования объектов в архив вызывается функция, которой передаются два аргумента:
1. объект File или Folder, который будет помещен в архив
2. объект Folder, виртуальная папка проводника, реализующая доступ к архиву
Пример 2. Чтение списка файлов из архива
var filename = 'test.zip';
WScript.Echo('*** Open the file');
var zipfile = new ZipFile(filename);
WScript.Echo('*** Show the content of the archive recursively');
zipfile.forEach(function(folderItem, arcfile)
{
if ( ! folderItem.IsFolder ) {
WScript.Echo(folderItem.Path, folderItem.Size);
return;
}
WScript.Echo(folderItem.Path);
var items = folderItem.GetFolder.Items();
var len = items.Count;
for (var i = 0; i < len; i++) {
var g = items.Item(i);
arguments.callee(g, arcfile);
}
});В этом примере открывается архивный файл test.zip и выводится рекурсивно список всех файлов и каталогов, содержащихся в архиве. Дополнительно, для каждого файла в архиве выводится его реальный размер. Метод вызывает заданную функцию для каждого объекта в архиве. В функцию передаются два аргумента:
1. объект File или Folder, находящийся в архиве
2. объект Folder, виртуальная папка проводника, реализующая доступ к архиву
***
Исходный код библиотеки
Здесь помещена последняя редакция библиотеки (удалена шапка с примерами, которые уже были рассмотрены чуть ранее). Актуальная версия доступна по адресу http://code.google.com/p/jsxt/source/br … ZipFile.js
/**
* Creates new object to work with archives. It can accept the same
* arguments as the ZipFile#open method. For details see the description
* of the method.
*
* @return ZipFile
* @acess public
* @see ZipFile#open
*/
function ZipFile()
{
if ( arguments.length == 0 ) {
return;
}
this.open.apply(this, arguments);
};
(function()
{
var fso = new ActiveXObject('Scripting.FileSystemObject');
var shellApp = new ActiveXObject("Shell.Application");
/**
* Opens a specified file. Creates a file if it was pointed. The name is
* mandatory argument passing the name of the existing archive or the name
* of the file that will be created. In the last case additional arguments
* are needed.
*
* @param String Mandatory. String expression that identifies the
* existing file or the file to create.
* @param Boolean Optional. Boolean value that indicates whether a
* new file can be created
* @param Boolean Optional. Boolean value that indicates whether you
* can overwrite an existing file. It depends on the
* create argument is true.
*
* @return void
* @acess public
*/
ZipFile.prototype.open = function(name, create, overwrite)
{
if ( create ) {
var zipFile = fso.CreateTextFile(name, !! overwrite, 0);
zipFile.Write('PK\05\06' + new Array(19).join('\0')); // 18 zeros
zipFile.Close();
}
this.name = fso.GetFile(name).Path;
this.file = shellApp.NameSpace(this.name);
};
/**
* Fake method. It allows a script to flush data to a disk to complete
* processing. In fact, it just suspends script execution for a specified
* length of time.
*
* @param Number Integer value indicating the interval (in
* milliseconds) you want the script process to be
* inactive.
*
* @return void
* @access public
*/
ZipFile.prototype.flush = function(timeout)
{
timeout = Math.max(Number(timeout) || 0, 100);
WScript.Sleep(timeout);
};
/**
* Executes a provided function once for each item from within a archive.
* Once called it allows to perform any action with items from an archive.
* The callback function is invoked with two arguments:
* -- The FolderItem argument refers to the real object (file or folder)
* within the archive
* -- The Folder object that refers to the archive file
*
* @param Function Mandatory. A function that will be called
* for each item in the archive
*
* @return void
* @access piblic
*/
ZipFile.prototype.forEach = function(func)
{
if ( typeof func != 'function' ) {
throw new TypeError();
}
var arcfile = this.file;
var items = arcfile.Items();
for (var e = new Enumerator(items); ! e.atEnd(); e.moveNext()) {
var folderItem = e.item();
func(folderItem, arcfile);
}
};
/**
* Executes a provided function once for each item before input it to the
* archive. Once called it allows to perform any action with items. The
* callback function is invoked with two arguments:
* -- The FolderItem argument refers to the real object (file or folder)
* before putting it into the archive
* -- The Folder object that refers to the archive file
*
* @param Array/String Mandatory. The list of items taht will be
* put into the archive.
* @param Function Mandatory. A function that will be called
* before an item will be put into the
* archive
*
* @return void
* @access piblic
*/
ZipFile.prototype.forInput = function(input, func)
{
if ( typeof func != 'function' ) {
throw new TypeError();
}
var arcfile = this.file;
if ( typeof input == 'string' ) {
input = [input];
}
for (var i = 0; i < input.length; i++) {
var p = input[i];
if ( ! p ) {
continue;
}
var folderItem = null;
if ( fso.FileExists(p) ) {
folderItem = fso.GetFile(p);
} else if ( fso.FolderExists(p) ) {
folderItem = fso.GetFolder(p);
}
func(folderItem, arcfile);
}
};
})();
