はじめに
「Scripting.FileSystemObject」と「Shell.Application」を利用して、ZIPファイルの圧縮や解凍をやってみます。
「CopyHere」メソッドによるZIP処理はエラー処理が不完全な事を理由に、
Microsoftでは「サポート対象外」となっていますので、確実にやりたい場合は、
コマンドラインの圧縮モジュールなどを使ったほうが良いかもしれません。
ファイルオブジェクトとシェルオブジェクトを定義します。
// ファイルオブジェクト取得
var fso = new ActiveXObject("Scripting.FileSystemObject");
// シェル取得
var shell = new ActiveXObject("Shell.Application");
圧縮
圧縮は以下の手順で行います。
- 空のZIPファイルを作成する。
- 空のZIPファイルにファイルをコピーする。
- ZIP圧縮中は読み書き禁止なので、読み書き出来るまで待機する。
空のZIPファイルは「End of central directory record」というZIPファイル情報を
ファイル0個ととして、新規ファイルに書き込みます。
バイナリーコードですので、「fromCharCode」メソッドを利用していったん文字列として書き込んでいます。
また、読み書き出来るまで待機する方法として、読み書き可能としてファイルを開き
エラーが出るか、出ないかで判断しています。
サンプルコードでは、
第1引数に、ZIPファイル
第2引数に、ファイル、フォルダ、または、ファイルとフォルダのリスト
を指定するようになっています。
function zip(zipfile, files) {
// ZIPに格納するアイテム
var items = [];
// ファイル存在チェック
if (files) {
// ファイル配列チェック
if (files instanceof Array) {
// 配列の場合はアイテムに設定
items = files;
} else {
// 配列ではないので、配列に追加
items.push(files);
}
}
// ZIPファイル存在チェック
if (!fso.FileExists(zipfile) && !fso.FolderExists(zipfile)) {
var ts = null;
try {
// ZIPファイル生成
ts = fso.OpenTextFile(zipfile, 2, true);
// 空のZIPファイル生成
ts.Write(String.fromCharCode(0x50, 0x4B, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00));
} catch (e) {
// エラーの場合
throw e;
} finally {
try {
if (ts != null) {
// ファイル閉じる
ts.Close();
}
} catch (e) {
// エラーの場合
throw e;
}
}
}
// 特殊フォルダ取得(ZIP)
var zip = shell.NameSpace(zipfile);
// アイテム数分ループ
for (var i = 0; i < items.length; i++) {
// ファイル又はフォルダ存在チェック
if (fso.FileExists(items[i]) || fso.FolderExists(items[i])) {
// ZIPファイルにコピー
zip.CopyHere(items[i], 4);
while (true) {
// 待機
WScript.Sleep(100);
try {
// ZIPファイルが読書可能かチェック
fso.OpenTextFile(zipfile, 8, false).Close();
// 可能な場合は終了
break;
} catch (e) {
// 不可能な場合は再度ループ
}
}
}
}
}
一応、「CopyHere」のオプション(第2引数)に、プログレスバー非表示(4)を設定しているんですが、
効いてないようです。
また、ZIPファイルの待機方法として、ZIPファイル内のファイル数で判定する方法もあるようです。
解凍
ZIPファイル内のファイルアイテムをフォルダにコピーします。
フォルダ生成には、前回作成した「createFolder」メソッドを利用しています。
こちらは、処理の待ち合わせが不要なようです・・・
function unzip(zipfile, folder) {
// ZIPファイル存在&拡張子判定
if (fso.FileExists(zipfile)
&& fso.GetExtensionName(zipfile).toLowerCase() == "zip") {
var unzip = null;
// パラメータチェック
if (folder) {
// フォルダ存在チェック
if (!fso.FolderExists(folder)) {
// フォルダが無い場合、生成
createFolder(folder);
}
// ZIPファイル名設定
unzip = folder;
}
// ZIPファイル存在チェック
if (unzip != null) {
// ZIP解凍
shell.NameSpace(folder).CopyHere(shell.NameSpace(zipfile).Items(), 20);
}
}
}
コマンドラインを利用した圧縮&解凍
ここで記述すべき事ではないかもしれませんが、一応「7-Zip」のコマンドライン版にて、圧縮&解凍してみます。
実行するjsと同じフォルダに、「7za.exe」と圧縮対象のファイル「log.txt」があるこを条件とします。
事前に以下が定義されているとします。
// ファイルオブジェクト取得
var fso = new ActiveXObject("Scripting.FileSystemObject");
// Scriptのカレントパス取得
var folderName = fso.GetParentFolderName(WScript.ScriptFullName);
// 「WScript.Shell」生成
var wshell = new ActiveXObject("WScript.Shell");
- 圧縮
// コマンド生成
var cmd = "\"" + folderName + "\\7za.exe\"" // 「7za.exe」パス
+ " a" // 追加
+ " \"" + folderName + "\\log.zip\"" // 圧縮ファイル
+ " \"" + folderName + "\\log.txt\""; // 圧縮対象ファイル
// コマンド実行
var exec = wshell.Exec(cmd);
// コマンド終了まで待機
while (exec.Status == 0) {
// 待機
WScript.Sleep(100);
}
- 解凍
// コマンド生成
var cmd = "\"" + folderName + "\\7za.exe\"" // 「7za.exe」パス
+ " x" // 解凍
+ " \"" + folderName + "\\log.zip\"" // 圧縮ファイル
+ " -o\"" + folderName + "\\log\""; // 解凍先
// コマンド実行
var exec = wshell.Exec(cmd);
// コマンド終了まで待機
while (exec.Status == 0) {
// 待機
WScript.Sleep(100);
}
コマンドラインですので、ここでは「7-Zip」版を使いましたがなんでも構いません。