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

У меня есть папка со следующей структурой

папка  вложенная папка (пусто)  вложенная  file1.bat  file2.bat  file3.bat

Как мне начать писать пакетный файл, чтобы заархивировать содержимое вышеуказанной папки без использования внешних программ, таких как winrar или 7zip?

Я попробовал код ниже. Но он скопировал бы содержимое в указанную папку temp без пустой папки, и при попытке застегнуть папку он будет только zip file1 и file2 и игнорировать остальную часть содержимого.

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

Я не мог найти причину проблемы. Любая помощь приветствуется.

set FILETOZIP=D:\OutputZipFiles\TestWorkDemo


set TEMPDIR=D:\OutputZipFiles\TempDir
rmdir %TEMPDIR%
mkdir %TEMPDIR%
xcopy /s %FILETOZIP% %TEMPDIR%

echo Set objArgs = WScript.Arguments > _zipIt.vbs
echo InputFolder = objArgs(0) >> _zipIt.vbs
echo ZipFile = objArgs(1) >> _zipIt.vbs
echo CreateObject("Scripting.FileSystemObject").CreateTextFile(ZipFile, True).Write "PK" ^& Chr(5) ^& Chr(6) ^& String(18, vbNullChar) >> _zipIt.vbs
echo Set objShell = CreateObject("Shell.Application") >> _zipIt.vbs
echo Set source = objShell.NameSpace(InputFolder).Items >> _zipIt.vbs
echo objShell.NameSpace(ZipFile).CopyHere(source) >> _zipIt.vbs
echo wScript.Sleep 2000 >> _zipIt.vbs

CScript  _zipIt.vbs  %TEMPDIR%  D:\OutputZipFiles\someArchive.zip

pause

Ответ 1

Как npocmaka сказал, Windows не может добавить одну пустую папку в zip файл либо через скриптинг, либо перетаскивание.

Но ты вдохновил меня. Я решил написать утилиту zip в JScript, просто чтобы узнать, могу ли я это сделать. Чтобы решить вашу текущую проблему, я добавил чек для пустых папок. Если пустая папка встречается, этот script создаст новую дочернюю папку в названии "(пустой)". Это было либо то, что добавить 0-байтовый файл, либо выбросить ошибку и пропустить добавление папки.

В любом случае, если вы хотите попробовать, сохраните этот script с расширением .bat и запустите его. Разумеется, это не так просто, как ваш VBscript, но он улучшил протоколирование, обработку ошибок и время; и он может застегивать отдельные файлы, а также папки.

@if (@[email protected]) @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.');
}

Преимущество использования JScript над VBScript здесь в том, что нет необходимости эхо-ответа на _zipIt.vbs. JScript предоставляет возможность быть оцененным inline как гибрид пакета script. У вашего vbscript, который вы разграбили, есть другая проблема, поскольку он произвольно вызывает WScript.Sleep 2000, независимо от того, сколько времени требуется для завершения копирования. Если вы копируете большие файлы, может быть недостаточно 2 секунд. И это расточительно, если вы копируете что-то маленькое.

Ответ 2

С Shell.Application уровнем 1 пустые папки всегда пропускаются. Вы можете самостоятельно протестировать выбор пустых файлов, включая пустые папки, и попытаться вставить их в zip файл через проводник Windows (что на самом деле является тем, что используется оболочкой приложение). В качестве обходного пути вы можете скопировать нужную папку в другую пустую папку и закрепить новую папку. Тогда у вас будут пустые каталоги уровня 2, которые должны быть заархивированы.