As npocmaka said, Windows can't add a single empty folder to a zip file either through scripting or drag-and-dropping.
But you've inspired me. I decided to write a zip utility in JScript, just to see whether I could. To address your current problem, I added a check for empty folders. If an empty folder is encountered, this script will create a new child folder within called "(empty)". It was either that, add a 0-byte file, or throw an error and skip adding the folder.
Anyway, if you'd like to try it, save this script with a .bat extension and run it. Granted, it's not as simple as your VBscript, but it's got better logging, error handling, and timing; and it can zip individual files as well as folders.
@if (@a==@b) @end /* JScript ignores this multiline comment
:: zip.bat file/folder1 [file/folder2 [file/folder3 etc...]] [-o outfile.zip]
:: creates a zip file
@echo off
setlocal enabledelayedexpansion
if "%~1"=="" (
echo Usage: %~nx0 [-o outfile.zip] "file1 or folder1" ["file2 or folder2"] etc.
echo If -o is not used, the zip file is named based on the first infile.
goto :EOF
)
:: convert wildcards to individual filenames
for %%I in (%*) do (
echo(%%I | findstr "[*?]" >NUL && (
for /f "tokens=*" %%x in ('dir /b %%I') do set "args=!args! "%%~fx""
) || set "args=!args! "%%~I""
)
if "!args!" equ "" (
echo(%* does not exist.
goto :EOF
)
cscript /nologo /e:Jscript "%~f0" !args!
goto :EOF
:: end of batch portion / begin JScript portion */
var files = [], outfile,
fso = new ActiveXObject("scripting.filesystemobject"),
shl = new ActiveXObject("shell.application");
function chr(n) { return String.fromCharCode(n); }
for (var i=0; i<WSH.Arguments.length; i++) {
if (WSH.Arguments(i).toLowerCase() == '-o') outfile = WSH.Arguments(++i);
else files.push(WSH.Arguments(i));
}
if (!outfile) try { outfile = files[0].split(/[/\]/)[0] + '.zip'; }
catch(e) { outfile = 'archive.zip'; } // Probably never see this, but just in case.
WSH.Echo('Creating ' + outfile);
var zip = fso.CreateTextFile(outfile);
zip.Write("PK" + chr(5) + chr(6));
for (var i=18; i>0; i--) zip.Write(chr(0));
zip.Close()
zip = shl.NameSpace(fso.GetFile(outfile).Path);
for (var i=0; i<files.length; i++) {
try {
if (fso.FileExists(files[i])) {
var file = fso.GetFile(files[i]);
} else if (fso.FolderExists(files[i])) {
var file = fso.GetFolder(files[i]);
if (!shl.NameSpace(file.Path).Items().Count) {
// Windows can't add an empty folder to a zip file, but
// it *can* add a folder that contains an empty folder.
shl.NameSpace(file.Path).NewFolder('(empty)');
}
} else {
throw "Unable to locate " + files[i];
}
var folder = shl.NameSpace(file.ParentFolder + '\'),
zipThis = folder.ParseName(fso.GetFileName(files[i]));
}
catch(e) {
var output = 'Skipping ' + files[i] + ': ';
output += (typeof e === 'string') ? e : (
e.description ? e.description : 'error ' + e.number + ' (unspecified error)'
);
WSH.Echo(output);
files.splice(i--,1);
continue;
}
WSH.StdOut.Write('Compressing ' + fso.GetFileName(file) + '... ');
zip.CopyHere(zipThis);
while (zip.Items().Count <= i) {
WSH.Sleep(50);
}
WSH.Echo('Done. (' + zip.Items().Count + ' of ' + files.length + ')');
}
if (!zip.Items().Count) {
fso.DeleteFile(fso.GetFile(outfile));
WSH.Echo('Zip file is empty. Deleting.');
}
The advantage of using JScript over VBScript here is that there's no need to echo out to _zipIt.vbs
. JScript affords the ability to be evaluated inline as a hybrid of a batch script. Your vbscript you plundered has another issue, in that it arbitrarily calls WScript.Sleep 2000
, regardless of how much time is needed to complete the copy. If you're copying large files, 2 seconds might not be enough time. And it's wasteful if you're copying something small.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…