UWSCでcab圧縮ファイルを扱う
多分こういう需要はあるんだろうな、、、と思いつつ、ネットの片隅に書いてみる。
標準のExpandコマンドとTempフォルダーを使って、UWSCスクリプトに内包したcabファイルを扱う。
スクリプト
cab.uws
OPTION EXPLICIT IFB GET_UWSC_NAME = "cab.uws" THEN // テスト用cabファイル生成 // cabファイル // .┬sub1 // | └sub.txt (sub1) // ├sub2 // | └sub.txt (sub2) // └root.txt (root) TEXTBLOCK CAB_DATA TVNDRgAAAACVAAAAAAAAACwAAAAAAAAAAwEBAAMAAACxDAAAfwAAAAEAAQAEAAAAAAAAAAAA L0KwTSAAcm9vdC50eHQABAAAAAQAAAAAAC9CvE0gAHN1YjFcc3ViLnR4dAAEAAAACAAAAAAA L0LCTSAAc3ViMlxzdWIudHh0AM91CoYOAAwAQ0srys8vKS5NMgRiIwA= ENDTEXTBLOCK // 設定する DIM res = Cab.SetCabData(CAB_DATA), ret = !CHKNUM(res) IF ret THEN MSGBOX("Cabモジュール管理下に一時ファイルが作成されました " + res) // 全て展開する res = 0 IF ret THEN res = Cab.Expand() IF !CHKNUM(res) THEN MSGBOX("全てを一時展開しました " + res) // root.txtを展開する DIM tar = "root.txt" IFB ret AND MSGBOX(tar + "を一時展開しますか?", BTN_YES OR BTN_NO) = BTN_YES THEN res = Cab.Expand(tar) IFB !CHKNUM(res) THEN MSGBOX(res + " に展開しました") IFB MSGBOX("展開した" + tar + "を、先に削除しますか?", BTN_YES OR BTN_NO) = BTN_YES THEN Cab.Dispose(res) ENDIF ELSE MSGBOX("展開に失敗しました") ENDIF ENDIF // sub.txtを展開する tar = "sub.txt" IFB ret AND MSGBOX(tar + "を一時展開しますか?", BTN_YES OR BTN_NO) = BTN_YES THEN res = Cab.Expand(tar) IFB !CHKNUM(res) THEN MSGBOX(res + " に展開しました") ELSE MSGBOX("展開に失敗しました") ENDIF ENDIF // 片付ける MSGBOX("一時展開したものを片付けます。path指定の展開は対象外です") Cab.Dispose() ENDIF MODULE Cab PUBLIC _fso DIM _path HASHTBL _tmps PROCEDURE Cab _fso = CreateOleObj("Scripting.FileSystemObject") _path = EMPTY FEND FUNCTION Dispose(tar=EMPTY, num=1) RESULT = TRUE IFB tar = EMPTY THEN WHILE LENGTH(_tmps) RESULT = RESULT AND Dispose(_tmps[0, HASH_KEY], _tmps[0, HASH_VAL]) WEND ELSE IFB _tmps[tar, HASH_EXISTS] THEN _tmps[tar] = _tmps[tar] - num IFB _tmps[tar] <= 0 THEN TRY RESULT = _tmps[tar, HASH_REMOVE] IFB _fso.FolderExists(tar) THEN _fso.DeleteFolder(tar) ELSEIF _fso.FileExists(tar) THEN _fso.DeleteFile(tar) ENDIF EXCEPT RESULT = FALSE ENDTRY ENDIF ENDIF ENDIF FEND FUNCTION GetTempPath() RESULT = _fso.GetSpecialFolder(2) + "\" + _fso.GetTempName() FEND FUNCTION SetCabFile(tar, temp=TRUE) RESULT = _fso.FileExists(tar) IFB RESULT THEN _path = tar IFB temp THEN _path = GetTempPath() TRY _fso.CopyFile(tar, _path) _tmps[_path] = 1 RESULT = _path EXCEPT RESULT = 1 ENDTRY ELSE RESULT = tar ENDIF ENDIF FEND FUNCTION SetCabData(data, path=EMPTY) IFB path = EMPTY THEN path = GetTempPath() _tmps[path] = 1 ENDIF DIM xml=CreateOleObj("Microsoft.XMLDOM"), t=xml.createElement("t"), s=CreateOleObj("ADODB.Stream") t.dataType = "bin.base64" t.text = data s.Open() s.Type=1 s.Write(t.nodeTypedValue) s.SaveToFile(path, 2) s.Close() RESULT = SetCabFile(path, FALSE) FEND FUNCTION Expand(tar="*", path=EMPTY, cab=EMPTY) IFB path = EMPTY THEN path = GetTempPath() _fso.CreateFolder(path) _tmps[path] = 1 ENDIF IF cab = EMPTY THEN cab = _path RESULT = EXEC("EXPAND " + cab + " -F:" + tar + " " + path, TRUE, ERR_VALUE, ERR_VALUE) IFB RESULT = 0 THEN RESULT = path ELSE Dispose(path) ENDIF FEND ENDMODULE
テストコードには、コメントで書いたようなcabファイルが書かれています。
このcabファイルの作り方は後述します。
Cab.SetCabDataでcabファイルを設定(一時フォルダーに作成)
(既存cabファイルを扱う場合、Cab.SetCabFileで)
Cab.Expandで一時フォルダーに全てを展開(戻りは展開先フォルダーかエラーコード)
Cab.Expandにファイル名を指定すると、そのファイルだけを展開。
展開先は、サブフォルダーの絡みがあるので、存在するフォルダーのみ指定可能です。
Cab.Disposeで、一時フォルダーの片付け。
指定した一時フォルダーのみ片付けることも可能。
他の操作をしたい場合、EXPANDコマンドのヘルプでも見て、がんばってくださいな。
- ファイル一覧はDオプションで取れるけど、パスが不明
- Rオプションでファイルを直接取り出せる、、、かも
- EXECだとコンソールウインドウが出てイマイチかも
cabファイルの作り方
makecabコマンドを使います。
大抵の環境には入っていると思います。
ただ使いにくいため、以下のスクリプトを用意しました。
が、さらに下のスクリプトの方が便利かもしれません。
mcab.js
// makecab utility WScript.Quit((function() { var ret = 0; // 引数チェック if(WScript.Arguments.Length < 2) { WScript.Echo('usage: (cab file path) (target dir)'); return 1; } var fso = WScript.CreateObject('Scripting.FileSystemObject'); var pathCab = WScript.Arguments.Item(0); if(fso.GetExtensionName(pathCab).toLowerCase() != 'cab') pathCab += '.cab'; var pathCabD = fso.GetSpecialFolder(2) + '\\' + fso.GetTempName(); var pathTemp = fso.GetSpecialFolder(2) + '\\' + fso.GetTempName(); // 出力先ファイルの有無確認 var preDel = false; if(fso.FileExists(pathCab)) { // 上書き確認して変更する //preDel = true; } // makecab用ファイルの作成 var tmp = fso.CreateTextFile(pathTemp, true); // 固定出力 tmp.WriteLine('.Set MaxCabinetSize=1073741824'); // 最大サイズは1GB tmp.WriteLine('.Set MaxDiskSize=1073741824'); tmp.WriteLine('.Set RptFilename=nul'); tmp.WriteLine('.Set InfFilename=nul'); tmp.WriteLine('.Set DiskDirectoryTemplate=' + pathCabD); // サブフォルダーの再帰処理用関数 var subFunc = function(tmp, fso, tar, s) { tmp.WriteLine('.Set DestinationDir="' + s + '"'); var f = fso.GetFolder(tar), fc; for(fc = new Enumerator(f.files); !fc.atEnd(); fc.moveNext()) { tmp.WriteLine('"' + fc.item() + '"'); } for(fc = new Enumerator(f.SubFolders); !fc.atEnd(); fc.moveNext()) { if(s.length > 0 && s.charAt(s.length-1) != '\\') s += '\\'; subFunc(tmp, fso, fc.item(), s + fso.GetFileName(fc.item())); } }; // 指定フォルダー内を列挙 for(var i=1; i<WScript.Arguments.Length; i++) { var tar = WScript.Arguments.Item(i); if(fso.FileExists(tar)) { tmp.WriteLine('.Set DestinationDir=""'); tmp.WriteLine('"' + tar + '"'); } else if(fso.FolderExists(tar)) { // フォルダーの場合は、内容を列挙 subFunc(tmp, fso, tar, ''); } else { WScript.Echo('File or Folder not found. ' + tar); } } tmp.Close(); // makecab実行 var wsh = WScript.CreateObject('WScript.Shell'); var oExec = wsh.Exec('makecab /F ' + pathTemp); WScript.Echo(oExec.StdOut.ReadAll()); while(oExec.Status == 0) { WScript.Sleep(100); } // tempファイル削除 try { fso.DeleteFile(pathTemp); } catch(e) { WScript.Echo('Delete ' + pathTemp + ' ' + e.name + '! ' + e.number + ' : ' + e.message); } // ファイルを移動 if(preDel) { try { fso.DeleteFile(pathCab); } catch(e) { WScript.Echo('Delete ' + pathCab + ' ' + e.name + '! ' + e.number + ' : ' + e.message); } } try { fso.MoveFile(pathCabD + '\\1.cab', pathCab); } catch(e) { switch(e.number) { case -2146828235: WScript.Echo('makecab output not found.'); break; case -2146828230: WScript.Echo('File already exists! ' + pathCab); break; default: WScript.Echo('MoveFile ' + pathCabD + '\\1.cab to ' + pathCab + ' ' + e.name + '! ' + e.number + ' : ' + e.message); break; } } try { fso.DeleteFolder(pathCabD); } catch(e) { WScript.Echo('Delete ' + pathCabD + ' ' + e.name + '! ' + e.number + ' : ' + e.message); } return ret; })());
「cscript //nologo mcab.js (cabファイル名) (対象フォルダー)」
対象フォルダーの中身をcabファイルに圧縮します。
cab操作スクリプト
ファイルをUWSCスクリプトにするスクリプト - じゅんじゅんのきまぐれ
とmcab.jsと最初のスクリプトを合成してみました。
これで、makecabコマンドのある環境なら、cab圧縮・展開ができますね。
cabUtil.uws
OPTION EXPLICIT IFB GET_UWSC_NAME = "cabUtil.uws" THEN // cabファイル // .┬sub1 // | └sub.txt (sub1) // ├sub2 // | └sub.txt (sub2) // └root.txt (root) TEXTBLOCK CAB_DATA TVNDRgAAAACVAAAAAAAAACwAAAAAAAAAAwEBAAMAAACxDAAAfwAAAAEAAQAEAAAAAAAAAAAA L0KwTSAAcm9vdC50eHQABAAAAAQAAAAAAC9CvE0gAHN1YjFcc3ViLnR4dAAEAAAACAAAAAAA L0LCTSAAc3ViMlxzdWIudHh0AM91CoYOAAwAQ0srys8vKS5NMgRiIwA= ENDTEXTBLOCK // cabファイル作成 DIM res = CabUtil.SetCabData(CAB_DATA), ret = !CHKNUM(res) IF ret THEN MSGBOX("Cabモジュール管理下に一時ファイルが作成されました " + res) // 全て展開する res = 0 IF ret THEN res = CabUtil.Expand() IF !CHKNUM(res) THEN MSGBOX("全てを一時展開しました " + res) // ファイル追加 IFB ret THEN DIM addFile = CabUtil._fso.CreateTextFile(res + "\add.txt") addFile.WriteLine("add file") addFile.Close() ENDIF // フォルダーcab圧縮 IFB ret THEN res = CabUtil.Contract(res) IF !CHKNUM(res) THEN MSGBOX("圧縮しました " + res) ENDIF // Base64表示 IFB ret AND !CHKNUM(res) THEN CabUtil.Log("<#CR><#CR>Base64") CabUtil.Log(CabUtil.ConvText(res)) ENDIF // 片付け CabUtil.Dispose() ENDIF MODULE CabUtil PUBLIC _fso DIM _path HASHTBL _tmps PROCEDURE CabUtil _fso = CreateOleObj("Scripting.FileSystemObject") _path = EMPTY FEND FUNCTION Dispose(tar=EMPTY, num=1) RESULT = TRUE IFB tar = EMPTY THEN WHILE LENGTH(_tmps) RESULT = RESULT AND Dispose(_tmps[0, HASH_KEY], _tmps[0, HASH_VAL]) WEND ELSE IFB _tmps[tar, HASH_EXISTS] THEN _tmps[tar] = _tmps[tar] - num IFB _tmps[tar] <= 0 THEN TRY RESULT = _tmps[tar, HASH_REMOVE] IFB _fso.FolderExists(tar) THEN _fso.DeleteFolder(tar) ELSEIF _fso.FileExists(tar) THEN _fso.DeleteFile(tar) ENDIF EXCEPT RESULT = FALSE ENDTRY ENDIF ENDIF ENDIF FEND FUNCTION GetTempPath() RESULT = _fso.GetSpecialFolder(2) + "\" + _fso.GetTempName() FEND FUNCTION SetCabFile(tar, temp=TRUE) RESULT = _fso.FileExists(tar) IFB RESULT THEN _path = tar IFB temp THEN _path = GetTempPath() TRY _fso.CopyFile(tar, _path) _tmps[_path] = 1 RESULT = _path EXCEPT RESULT = 1 ENDTRY ELSE RESULT = tar ENDIF ENDIF FEND FUNCTION SetCabData(data, path=EMPTY) IFB path = EMPTY THEN path = GetTempPath() _tmps[path] = 1 ENDIF DIM xml=CreateOleObj("Microsoft.XMLDOM"), t=xml.createElement("t"), s=CreateOleObj("ADODB.Stream") t.dataType = "bin.base64" t.text = data s.Open() s.Type=1 s.Write(t.nodeTypedValue) s.SaveToFile(path, 2) s.Close() RESULT = SetCabFile(path, FALSE) FEND FUNCTION Expand(tar="*", path=EMPTY, cab=EMPTY) IFB path = EMPTY THEN path = GetTempPath() _fso.CreateFolder(path) _tmps[path] = 1 ENDIF IF cab = EMPTY THEN cab = _path RESULT = EXEC("EXPAND " + cab + " -F:" + tar + " " + path, TRUE, ERR_VALUE, ERR_VALUE) IFB RESULT = 0 THEN RESULT = path ELSE Dispose(path) ENDIF FEND PROCEDURE Log(msg) PRINT msg FEND PROCEDURE ContractSub(tmp, fso, tar, s) tmp.WriteLine(".Set DestinationDir=<#DBL>" + s + "<#DBL>") DIM f = fso.GetFolder(tar), i FOR i = 0 TO GETOLEITEM(f.files) - 1 tmp.WriteLine("<#DBL>" + ALL_OLE_ITEM[i].Path + "<#DBL>"); NEXT FOR i = 0 TO GETOLEITEM(f.SubFolders) - 1 IFB LENGTH(s) > 0 THEN IF COPY(s, LENGTH(s), 1) <> "\" THEN s = s + "\" ENDIF ContractSub(tmp, fso, ALL_OLE_ITEM[i].Path, s + ALL_OLE_ITEM[i].Name) NEXT FEND FUNCTION Contract(path, cab=EMPTY, cap=1073741824) IFB cab = EMPTY THEN cab = GetTempPath() _tmps[cab] = 1 ENDIF DIM preDel = FALSE // makecab用ファイルの作成 DIM pathCabD = GetTempPath(), pathTemp = GetTempPath() DIM tmp = _fso.CreateTextFile(pathTemp, TRUE) // 固定出力 tmp.WriteLine(".Set MaxCabinetSize=" + cap) tmp.WriteLine(".Set MaxDiskSize=1073741824" + cap) tmp.WriteLine(".Set RptFilename=nul") tmp.WriteLine(".Set InfFilename=nul") tmp.WriteLine(".Set DiskDirectoryTemplate=" + pathCabD) // 指定ディレクトリー内を列挙 DIM i IFB VARTYPE(path) < VAR_ARRAY THEN i = path path = SAFEARRAY(0, 0) path[0] = i ENDIF FOR i = 0 TO LENGTH(path) - 1 IFB _fso.FileExists(path[i]) THEN tmp.WriteLine(".Set DestinationDir=<#DBL><#DBL>") tmp.WriteLine("<#DBL>" + path[i] + "<#DBL>") ELSEIF _fso.FolderExists(path[i]) THEN ContractSub(tmp, _fso, path[i], "") ELSE Log("File or Folder not found. " + path[i]) ENDIF NEXT tmp.Close() // makecab実行 Log(DOSCMD("makecab /F " + pathTemp)) // tempファイル削除 _fso.DeleteFile(pathTemp) // ファイルを移動 IF preDel THEN _fso.DeleteFile(cab) _fso.MoveFile(pathCabD + "\1.cab", cab) _fso.DeleteFolder(pathCabD); RESULT = cab FEND FUNCTION ConvText(path) RESULT = "" // ファイル読み込み DIM ins = CreateOleObj("ADODB.Stream") ins.Open() ins.Charset = "iso-8859-1" ins.Type = 1 // Binary ins.LoadFromFile(path) // バイト配列操作用オブジェクト DIM dom = CreateOleObj("Microsoft.XMLDOM"), binMan = dom.createElement("tmp") binMan.dataType = "bin.base64" DIM loop = TRUE WHILE loop binMan.nodeTypedValue = ins.Read(54) loop = (LENGTH(binMan.text) > 0) IF loop THEN RESULT = RESULT + "<#CR>" + binMan.text WEND ins.Close() ins = Nothing binMan = Nothing dom = Nothing FEND ENDMODULE
あまり大きなcabファイルになると、メモリーがきついことになりそう、、、。
ファイルを暗号化したい?
一時ファイルを作成してしまうつくりですからねぇ、、、あまり意味ないかと。
それでもしたいなら、
UWSCでWin32 Crypto APIを使う - じゅんじゅんのきまぐれ
を参照してがんばってくださいな。