如何在不使用任何外部工具的情况下使用批处理文件压缩(/ zip)和解压缩(/解压缩)文件和文件夹?

npo*_*aka 42 .net zip batch-file jscript

我知道这里有很多类似的问题,但我对答案(甚至是问题)都不满意.

主要目标是兼容性 - 它应该适用于最广泛的Windows机器(包括XP,Vista,Win2003 - 它们共同占据了大约20%的Windows共享),并且生成的文件应该可以在Unix/Mac机器上使用(所以标准存档/压缩格式是优选的).

选项有哪些:

  1. 创建一个实现一些zip算法的批处理.显然这是可能的 - 但只能使用单个文件并使用CERTUTIL进行二进制处理(某些机器默认情况下没有CERTUTIL,并且无法在WinXP Home Edition上安装)
  2. 通过WSH 使用shell.application.根据我的最佳选择.它允许压缩整个目录,并且可以在每台Windows机器上使用
  3. Makecab - 尽管压缩不是那么便携,但它可以在每台Windows机器上使用.一些外部程序如7zip能够提取.CAB内容,但是当需要在Unix/Mac上使用文件时它会不那么方便.并且压缩时单个文件非常简单,保留目录结构需要更多的努力.
  4. 使用.NET Framework - 不是那么好的选项.Form .NET 2.0有 GZipStream但它只允许压缩单个文件..NET 4.5具有Zip功能,但在Vista和XP上不支持.甚至更多 - 默认情况下不会在XP和Win2003上安装.NET,但由于很可能将.NET 2.0升级到4.0,因此它是一个相当大的选择.
  5. Powershell - 因为它依赖于.NET,它具有相同的功能.默认情况下,它不会安装在XP,2003和Vista上,所以我会跳过它.

npo*_*aka 58

以下是答案:

1.使用"纯"批处理脚本来压缩/解压缩文件.

这可能要归功于Frank Westlake的ZIP.CMDUNZIP.CMD(需要管理员权限和要求FSUTILCERTUTIL).对于Win2003和WinXP,它将需要 安装2003 Admin Tool PackCERTUTIL.注意ZIP.CMD语法是向后的:

ZIP.CMD destination.zip source.file
Run Code Online (Sandbox Code Playgroud)

它只能压缩单个文件.

2.使用Shell.Application

我花了一些时间来创建一个单独的jscript/batch混合脚本,用于拉链/解压缩文件和目录(以及更多功能)的常见用法.这是一个链接(它变得太大了,无法在答案中发布).可以直接与其.bat扩展名一起使用,也不会创建任何临时文件.我希望帮助信息足够描述如何使用它.

一些例子:

// unzip content of a zip to given folder.content of the zip will be not preserved (-keep no).Destination will be not overwritten (-force no)
call zipjs.bat unzip -source C:\myDir\myZip.zip -destination C:\MyDir -keep no -force no

// lists content of a zip file and full paths will be printed (-flat yes)
call zipjs.bat list -source C:\myZip.zip\inZipDir -flat yes

// lists content of a zip file and the content will be list as a tree (-flat no)
call zipjs.bat list -source C:\myZip.zip -flat no

// prints uncompressed size in bytes
zipjs.bat getSize -source C:\myZip.zip

// zips content of folder without the folder itself
call zipjs.bat zipDirItems -source C:\myDir\ -destination C:\MyZip.zip -keep yes -force no

// zips file or a folder (with the folder itslelf)
call zipjs.bat zipItem -source C:\myDir\myFile.txt -destination C:\MyZip.zip -keep yes -force no

// unzips only part of the zip with given path inside
call zipjs.bat unZipItem -source C:\myDir\myZip.zip\InzipDir\InzipFile -destination C:\OtherDir -keep no -force yes
call zipjs.bat unZipItem -source C:\myDir\myZip.zip\InzipDir -destination C:\OtherDir 

// adds content to a zip file
call zipjs.bat addToZip -source C:\some_file -destination C:\myDir\myZip.zip\InzipDir -keep no
call zipjs.bat addToZip -source  C:\some_file -destination C:\myDir\myZip.zip
Run Code Online (Sandbox Code Playgroud)

压缩过程中的一些已知问题:

  • 如果系统驱动器上没有足够的空间(通常是C :),脚本可能会产生各种错误,通常是脚本停止.这是由于Shell.Application主动使用%TEMP%文件夹来压缩/解压缩数据.
  • Shell.Application对象无法处理名称中包含unicode符号的文件夹和文件.
  • 在Vista及以上版本中,生成的zip文件的最大支持大小约为8GB,在XP/2003中约为2gb

该脚本检测是否弹出错误消息并停止执行并通知可能的原因.此时我无法检测弹出窗口中的文本并提供失败的确切原因.

3. Makecab.

压缩文件很简单 - makecab file.txt "file.cab".最终可以增加MaxCabinetSize.压缩文件夹需要为每个(子)目录和其中的文件使用DestinationDir指令(具有相对路径).这是一个脚本:

;@echo off

;;;;; rem start of the batch part  ;;;;;
;
;for %%a in (/h /help -h -help) do ( 
;   if /I "%~1" equ "%%~a" if "%~2" equ "" (
;       echo compressing directory to cab file  
;       echo Usage:
;       echo(
;       echo %~nx0 "directory" "cabfile"
;       echo(
;       echo to uncompress use:
;       echo EXPAND cabfile -F:* .
;       echo(
;       echo Example:
;       echo(
;       echo %~nx0 "c:\directory\logs" "logs"
;       exit /b 0
;   )
; )
;
; if "%~2" EQU "" (
;   echo invalid arguments.For help use:
;   echo %~nx0 /h
;   exit /b 1
;)
;
; set "dir_to_cab=%~f1"
;
; set "path_to_dir=%~pn1"
; set "dir_name=%~n1" 
; set "drive_of_dir=%~d1"
; set "cab_file=%~2"
;
; if not exist %dir_to_cab%\ (
;   echo no valid directory passed
;   exit /b 1
;)

;
;break>"%tmp%\makecab.dir.ddf"
;
;setlocal enableDelayedExpansion
;for /d /r "%dir_to_cab%" %%a in (*) do (
;   
;   set "_dir=%%~pna"
;   set "destdir=%dir_name%!_dir:%path_to_dir%=!"
;   (echo(.Set DestinationDir=!destdir!>>"%tmp%\makecab.dir.ddf")
;   for %%# in ("%%a\*") do (
;       (echo("%%~f#"  /inf=no>>"%tmp%\makecab.dir.ddf")
;   )
;)
;(echo(.Set DestinationDir=!dir_name!>>"%tmp%\makecab.dir.ddf")
;   for %%# in ("%~f1\*") do (
;       
;       (echo("%%~f#"  /inf=no>>"%tmp%\makecab.dir.ddf")
;   )

;makecab /F "%~f0" /f "%tmp%\makecab.dir.ddf" /d DiskDirectory1=%cd% /d CabinetNameTemplate=%cab_file%.cab
;rem del /q /f "%tmp%\makecab.dir.ddf"
;exit /b %errorlevel%

;;
;;;; rem end of the batch part ;;;;;

;;;; directives part ;;;;;
;;
.New Cabinet
.set GenerateInf=OFF
.Set Cabinet=ON
.Set Compress=ON
.Set UniqueFiles=ON
.Set MaxDiskSize=1215751680;

.set RptFileName=nul
.set InfFileName=nul

.set MaxErrors=1
;;
;;;; end of directives part ;;;;;
Run Code Online (Sandbox Code Playgroud)

对于解压缩EXPAND cabfile -F:* .可以使用.对于Unix中的提取,可以使用cabextract7zip.

4. .NET和GZipStream

我更喜欢Jscript.net,因为它允许与.bat进行整齐的杂交(没有有毒输出,没有临时文件).Jscript不允许将对象的引用传递给函数,所以我发现让它工作的唯一方法是逐字节读/写文件(所以我想这不是最快的方法 - 如何进行缓冲读/写?)再次只能用于单个文件.

@if (@X)==(@Y) @end /* JScript comment
@echo off
setlocal

for /f "tokens=* delims=" %%v in ('dir /b /s /a:-d  /o:-n "%SystemRoot%\Microsoft.NET\Framework\*jsc.exe"') do (
   set "jsc=%%v"
)

if not exist "%~n0.exe" (
    "%jsc%" /nologo /out:"%~n0.exe" "%~dpsfnx0"
)

 %~n0.exe %*

endlocal & exit /b %errorlevel%


*/


import System;
import System.Collections.Generic;
import System.IO;
import System.IO.Compression;



    function CompressFile(source,destination){
        var sourceFile=File.OpenRead(source);
        var destinationFile=File.Create(destination);
        var output = new  GZipStream(destinationFile,CompressionMode.Compress);
        Console.WriteLine("Compressing {0} to {1}.", sourceFile.Name,destinationFile.Name, false);
        var byteR = sourceFile.ReadByte();
        while(byteR !=- 1){
            output.WriteByte(byteR);
            byteR = sourceFile.ReadByte();
        }
        sourceFile.Close();
        output.Flush();
        output.Close();
        destinationFile.Close();
    }

    function UncompressFile(source,destination){
        var sourceFile=File.OpenRead(source);
        var destinationFile=File.Create(destination);

        var input = new GZipStream(sourceFile,
            CompressionMode.Decompress, false);
        Console.WriteLine("Decompressing {0} to {1}.", sourceFile.Name,
                destinationFile.Name);

        var byteR=input.ReadByte();
        while(byteR !== -1){
            destinationFile.WriteByte(byteR);
            byteR=input.ReadByte();
        }
        destinationFile.Close();
        input.Close();


    }

var arguments:String[] = Environment.GetCommandLineArgs();

    function printHelp(){
        Console.WriteLine("Compress and uncompress gzip files:");
        Console.WriteLine("Compress:");
        Console.WriteLine(arguments[0]+" -c source destination");
        Console.WriteLine("Uncompress:");
        Console.WriteLine(arguments[0]+" -u source destination");


    }

if (arguments.length!=4){
    Console.WriteLine("Wrong arguments");
    printHelp();
    Environment.Exit(1);
}

switch (arguments[1]){
    case "-c":

        CompressFile(arguments[2],arguments[3]);
        break;
    case "-u":
        UncompressFile(arguments[2],arguments[3]);
        break;
    default:
        Console.WriteLine("Wrong arguments");
        printHelp();
        Environment.Exit(1);
}
Run Code Online (Sandbox Code Playgroud)

  • 绝对是最全面的解决方案集合. (4认同)
  • ZIP.CMD 和 UNZIP.cmd 链接都在此日期导致 404 错误。 (3认同)
  • 它确实是一个很好的解决方案集合.我最喜欢`zipjs.bat`的解决方案2.但我对`zipjs.bat`有一个增强请求.在ZIP文件的__unzip__上,它在`%TEMP%`中留下了暂时用于从ZIP文件中提取每个文件的子目录和文件.如果这个混合批处理文件会自行删除它们会很好,请参阅我的答案[如何编写一个可以将文件解压缩到一个同名新文件夹的批处理文件?](http://stackoverflow.com/一个/三百○七万四​​千五百六十四分之三千一百五十○万二千五百三十六) (2认同)

Ild*_*lde 5

惊人的解决方案!

Makecab解决方案存在一些问题,因此,这里是一个固定版本,可以解决在使用带空格的目录时解决的问题。

;@echo off

;;;;; rem start of the batch part  ;;;;;
;
;for %%a in (/h /help -h -help) do ( 
;   if /I "%~1" equ "%%~a" if "%~2" equ "" (
;       echo compressing directory to cab file  
;       echo Usage:
;       echo(
;       echo %~nx0 "directory" "cabfile"
;       echo(
;       echo to uncompress use:
;       echo EXPAND cabfile -F:* .
;       echo(
;       echo Example:
;       echo(
;       echo %~nx0 "c:\directory\logs" "logs"
;       exit /b 0
;   )
; )
;
; if "%~2" EQU "" (
;   echo invalid arguments.For help use:
;   echo %~nx0 /h
;   exit /b 1
;)
;
; set "dir_to_cab=%~f1"
;
; set "path_to_dir=%~pn1"
; set "dir_name=%~n1" 
; set "drive_of_dir=%~d1"
; set "cab_file=%~2"
; 
; if not exist "%dir_to_cab%\" (
;   echo no valid directory passed
;   exit /b 1
;)

;
;break>"%tmp%\makecab.dir.ddf"
;
;setlocal enableDelayedExpansion
;for /d /r "%dir_to_cab%" %%a in (*) do (
;   
;   set "_dir=%%~pna"
;   set "destdir=%dir_name%!_dir:%path_to_dir%=!"
;   (echo(.Set DestinationDir=!destdir!>>"%tmp%\makecab.dir.ddf")
;   for %%# in ("%%a\*") do (
;       (echo("%%~f#"  /inf=no>>"%tmp%\makecab.dir.ddf")
;   )
;)
;(echo(.Set DestinationDir=!dir_name!>>"%tmp%\makecab.dir.ddf")
;   for %%# in ("%~f1\*") do (
;       
;       (echo("%%~f#"  /inf=no>>"%tmp%\makecab.dir.ddf")
;   )

;makecab /F "%~f0" /f "%tmp%\makecab.dir.ddf" /d DiskDirectory1="%cd%" /d CabinetNameTemplate=%cab_file%.cab
;rem del /q /f "%tmp%\makecab.dir.ddf"
;exit /b %errorlevel%

;;
;;;; rem end of the batch part ;;;;;

;;;; directives part ;;;;;
;;
.New Cabinet
.set GenerateInf=OFF
.Set Cabinet=ON
.Set Compress=ON
.Set UniqueFiles=ON
.Set MaxDiskSize=1215751680;

.set RptFileName=nul
.set InfFileName=nul

.set MaxErrors=1
;;
;;;; end of directives part ;;;;;
Run Code Online (Sandbox Code Playgroud)


npo*_*aka 5

使用Compress-ArchiveExpand-Archive的 powershell 的一些示例:

//zipping folder or file:
powershell "Compress-Archive -Path """C:\some_folder""" -DestinationPath """zippedFolder.zip""""

//unzipping folder:
powershell "Expand-Archive -Path """Draftv2.Zip""" -DestinationPath """C:\Reference""""
Run Code Online (Sandbox Code Playgroud)

与当前支持的 Windows 版本一样,默认情况下会安装这些 cmd-let。

使用 powershell 的另一种方法

//zip directory
powershell "Add-Type -Assembly """System.IO.Compression.FileSystem""" ;[System.IO.Compression.ZipFile]::CreateFromDirectory("""C:\some_dir""", """some.zip""");"

//unzip directory
powershell "Add-Type -Assembly "System.IO.Compression.FileSystem" ;[System.IO.Compression.ZipFile]::ExtractToDirectory("""yourfile.zip""", """c:\your\destination""");"
Run Code Online (Sandbox Code Playgroud)