Работа с ZIP-архивами из-под lisp’a

Понадобилось мне тут обрабатывать zip-архивы. Казалось бы, все должно быть просто, поскольку обработка zip-архивов уже в Windows встроена. Ан нет, ни фига.

Недолгий поиск привел на темы http://www.theswamp.org/index.php?topic=37416.0 и http://www.theswamp.org/index.php?topic=31097.msg366864#msg366864. И я радостно стал использовать представленные там коды.

Правда, счастье было неполным и очень недолгим. Причин оказалось несколько: как выяснилось, только операции с одиночными файлами (заархивировать, распаковать и т.п.) выполняются на ура. Как только надо обработать что-то пакетно (запаковать, например, каталог со всеми подкаталогами; или распаковать) - начинаются чудеса. И заключаются они в том, что при пакетной обработке какие-то файлы могут запросто не заархивироваться. Или не распаковаться.

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

Так, для распаковки можно сделать vbs-файл и заставить его выполняться:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
(defun _kpblc-zip-extract-allfiles (zipfile strdest / file handle wscript)
;|
* Извлечение всех файлов из zip-архива (включая подкаталоги). Источник:
* http://www.theswamp.org/index.php?topic=31097.0
* Параметры вызова:
zipfile Полное имя zip-архива
strdest Путь, куда выполнять разархивирование.
* Пример вызова:
(_kpblc-zip-extract-allfiles "C:\\pack.zip" "C:\\updates")
|;
(setq file (strcat (vl-string-right-trim "\" (getenv "temp")) "\\unzip.vbs")
handle (open file "
w")
) ;_ end of setq
(foreach item (list (strcat "
ZipFile="" zipfile """)
(strcat "
ExtractTo="" strdest """)
"
'If the extraction location does not exist create it."
"
Set fso = CreateObject("Scripting.FileSystemObject")"
"
If NOT fso.FolderExists(ExtractTo) Then"
"
fso.CreateFolder(ExtractTo)"
"
End If"
"
'Extract the contants of the zip file."
"
set objShell = CreateObject("Shell.Application")"
"
set FilesInZip=objShell.NameSpace(ZipFile).items"
"
objShell.NameSpace(ExtractTo).CopyHere(FilesInZip)"
"
Set fso = Nothing"
"
Set objShell = Nothing"
) ;_ end of list
(write-line item handle)
) ;_ end of foreach
(close handle)
(if (setq wscript (vlax-get-or-create-object "
WScript.Shell"))
(vl-catch-all-apply (function (lambda () (vlax-invoke-method wscript "
Run" file 0 :vlax-true))))
) ;_ end of if
(vl-catch-all-apply (function (lambda () (vlax-release-object wscript))))
(vl-file-delete file)
) ;_ end of defun

Честно скажу, код VBS не мой, спер откуда-то.
Чем хорош подобный код - так это тем, что каталог вроде бы даже и создавать предварительно не надо, эту работу выполнит VBS. Чем плох - так это тем, что админы "с добрыми усталыми глазами и печальной улыбкой на лице" могут заблокировать выполнение VBS-кода. Ну, если заблокируют, буду придумывать что-нибудь еще.

С архивированиеи я решил задачу по-другому. Попытался в очередной раз использовать C#:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using System;
using System.IO;
using System.IO.Compression;
using System.Security.Cryptography;

using AcRt = Autodesk.AutoCAD.Runtime;
using AcDb = Autodesk.AutoCAD.DatabaseServices;

namespace kpblc
{
[AcRt.LispFunction("_kpblc-zipfolder")]
public static bool kpblc_zipfolder(AcDb.ResultBuffer arguments)
{
bool res = false ;
if (arguments != null)
{
Array args = arguments.AsArray();
string zipDest = System.Convert.ToString(((AcDb.TypedValue)(args.GetValue(0))).Value);
string folderName = System.Convert.ToString(((AcDb.TypedValue)(args.GetValue(1))).Value);
try
{
ZipFile.CreateFromDirectory(folderName, zipDest, CompressionLevel.Optimal, false);
res = true;
}
catch
{
res = false;
}
}
return res;
}

}
}

Сборка всяко загружается внутрь ACAD'a, так что можно спокойно использовать _kpblc-zipfolder и не париться.

Размещено в .NET, AutoCAD, Код LISP, Функции LISP · Метки: , , ,



Поделитесь своим мнением


Я не робот.