如何使用批處理文件壓縮(/ zip)和解壓(/ unzip)文件和文件夾,而不使用任何外部工具?

[英]How can I compress (/ zip ) and uncompress (/ unzip ) files and folders with batch file without using any external tools?


I know the similar question were asked here a lot , but I'm not completely satisfied with the answers (and even with the questions).

我知道這里有很多類似的問題,但我對答案(甚至是問題)並不完全滿意。

The main goal is compatibility - it should be applicable to widest possible range of windows machines (including XP,Vista,Win2003 - which together still holds around 20% of windows share ) and produced files should be usable on Unix/Mac machines (so standard archiving/compression formats are preferable).

它的主要目標是兼容性——它應該適用於最廣泛的windows機器(包括XP、Vista、Win2003——它們仍然擁有大約20%的windows份額),並且產生的文件應該在Unix/Mac機器上可用(所以標准的歸檔/壓縮格式更可取)。

What the options are :

選擇是什么:

  1. Creating a batch that implements some zip algorithm. Apparently this is possible - but only with single files and using CERTUTIL for binary processing (some machines does not have CERTUTIL by default and is not possible to be installed on WinXP Home Edition)
  2. 創建實現某種zip算法的批處理。顯然,這是可能的——但是只使用單個文件,並使用CERTUTIL進行二進制處理(一些機器默認沒有CERTUTIL,並且不可能安裝在WinXP Home Edition上)
  3. Using shell.application through WSH.The best option according to me.It allows zipping whole directories and is usable on every windows machine
  4. 使用shell。應用程序通過WSH。我認為是最好的選擇。它允許對整個目錄進行壓縮,並且適用於所有windows機器
  5. Makecab - despite its compression is not so portable its available on every windows machine.Some external programs like 7zip are capable to extract .CAB content ,but it will be not so convenient when files need to be used on Unix/Mac.And while compressing a single file is pretty straightforward , preserving directory structure requires a little bit more effort.
  6. Makecab -盡管它的壓縮在每個windows機器上都不是很便攜。一些像7zip這樣的外部程序可以提取. cab內容,但是當需要在Unix/Mac上使用文件時就不那么方便了。雖然壓縮單個文件非常簡單,但是保存目錄結構需要更多的努力。
  7. Using .NET Framework - not so good option.Form .NET 2.0 there is GZipStream but it allows compression only of single files. .NET 4.5 has Zip capabilities but it's not supported on Vista and XP .And even more - .NET is not installed by default on XP and Win2003 , but as it is highly probable to have .NET 2.0 up-to 4.0 it's a considerable opion.
  8. 使用。net框架-不是很好的選擇。形式。net 2.0 GZipStream但它允許壓縮只有單一文件。net 4.5 Zip功能但不支持Vista和XP,更多- net XP和Win2003不是默認安裝,但它是非常可能的。net 2.0達到4.0,這是一個相當大的見解。
  9. Powershell - as it relies on .NET it has same capabilities.It's not installed by default on XP,2003 and Vista so I'll skip it.
  10. Powershell——因為它依賴於。net,所以它也有同樣的功能。它不是默認安裝在XP,2003和Vista上,所以我跳過它。

3 个解决方案

#1


52  

And here are the answer(s):

答案是:

1.Using "pure" batch script to zip/unzip file.

1。使用“純”批處理腳本壓縮/解壓縮文件。

It's possible thanks to Frank Westlake's ZIP.CMD and UNZIP.CMD(needs admin permissions and requires FSUTIL and CERTUTIL) .For Win2003 and WinXP it will require 2003 Admin Tool Pack which will install CERTUTIL. Be careful as ZIP.CMD syntax is backward :

多虧了弗蘭克·韋斯特萊克的拉鏈。CMD並解壓縮。CMD(需要管理權限,需要FSUTIL和CERTUTIL)。對於Win2003和WinXP,它需要2003年的管理工具包來安裝CERTUTIL。小心ZIP。CMD語法是向后的:

ZIP.CMD destination.zip source.file

And it can zip only single files.

而且它只能壓縮單個文件。

2.Using Shell.Application

2。使用Shell.Application

I've spent some time to create a single jscript/batch hybrid script for common usage that zips/unzips files and directories (plus few more features).Here's a link to it (it became too big to post in the answer). Can be used directly with its .bat extension and does not create any temp files. I hope the help message is descriptive enough of how it can be used.

我已經花了一些時間來創建一個jscript/batch混合腳本,用於壓縮/解壓縮文件和目錄(再加上一些其他特性)的通用使用。這里有一個鏈接(它太大了以至於不能在答案中發布)。可以直接使用它的.bat擴展名,不創建任何臨時文件。我希望幫助消息足夠描述如何使用它。

Some examples:

一些例子:

// 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

Some known issues during zipping:

一些已知的問題在zipping:

  • if there's not enough space on the system drive (usually C:) the script could produce various errors , most often the script halts.This is due to Shell.Application actively uses %TEMP% folder to compress/decompress the data.
  • 如果系統驅動器上沒有足夠的空間(通常是C:),腳本可能會產生各種錯誤,通常腳本會停止。這是殼層造成的。應用程序積極使用%TEMP%文件夾來壓縮/解壓縮數據。
  • Folders and files that contain unicode symbols in their names cannot be handled by Shell.Application object.
  • 在名稱中包含unicode符號的文件夾和文件不能由Shell處理。應用程序對象。
  • Max supported size of produced zip files is around 8gb in Vista and above and around 2gb in XP/2003
  • 在Vista和以上版本中,最大支持的zip文件大小在8gb左右,在XP/2003版本中大約為2gb

The script detects if error message pops-up and stops the execution and informs for the possible reasons.At the moment I have no way to detect the text inside the pop-up and give the exact reason for the failure.

腳本檢測錯誤消息是否彈出並停止執行,並根據可能的原因通知。目前我無法檢測彈出框中的文本並給出失敗的確切原因。

3.Makecab.

3. makecab。

Compressing a file is easy - makecab file.txt "file.cab" . Eventually MaxCabinetSize could be increased. Compressing a folder requires a usage DestinationDir directive (with relative paths) for every (sub)directory and the files within . Here's a script:

壓縮文件很容易- makecab文件。txt文件。出租車”。最終可以增加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 ;;;;;

For decompression EXPAND cabfile -F:* . can be used.For extraction in Unix cabextract or 7zip can be used.

對於解壓縮,展開cabfile -F:*。可以使用。可以使用Unix cabextract或7zip中的提取。

4. .NET and GZipStream

4 . net和GZipStream

I preferred a Jscript.net as it allows a neat hybridization with .bat (no toxic output , and no temp files).Jscript does not allow passing a reference of object to a function so the only way I found to make it work is by reading/writing files byte by byte (so I suppose it's not the fastest way - how buffered reading/writing can be done?)Again can be used only with single files.

我更喜歡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);
}

#2


4  

amazing solutions!

神奇的解決方案!

The makecab solution has some issues so here is a fixed version that solves the problem when using directories with blank spaces.

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 ;;;;;

#3


1  

CAB.bat [input] folder or file : pack | .cab or .??_ : unpack | none : pack a files subfolder
Will also add a CAB entry to right-click SendTo menu for easy handling
Since this one does both tasks seamlessly, it should be preferred over the ugly makecab one - why use hybrid script if you write to temp file anyway?

出租車。bat[輸入]文件夾或文件:打包| .cab or .?_:解壓|沒有:打包文件文件夾也將添加一個出租車進入右鍵發送到菜單簡單無縫地處理這一任務以來,它應該優先於丑makecab——為什么使用混合腳本如果寫入臨時文件呢?

@echo off &echo. &set "ext=%~x1" &title CAB [%1] &rem input file or folder / 'files' folder / unpacks .cab .??_
if "_%1"=="_" if not exist "%~dp0files" echo CAB: No input and no 'files' directory to pack &goto :Exit "do nothing"
if "_%1"=="_" if exist "%~dp0files" call :CabDir "%~dp0files" &goto :Exit "input = none, use 'files' directory -pack" 
for /f "tokens=1 delims=r-" %%I in ("%~a1") do if "_%%I"=="_d" call :CabDir "%~f1" &goto :Exit "input = dir -pack"
if not "_%~x1"=="_.cab" if not "_%ext:~-1%"=="__" call :CabFile "%~f1" &goto :Exit "input = file -pack"
call :CabExtract "%~f1" &goto :Exit "input = .cab or .??_ -unpack" 
:Exit AveYo: script will add a CAB entry to right-click -- SendTo menu
if not exist "%APPDATA%\Microsoft\Windows\SendTo\CAB.bat" copy /y "%~f0" "%APPDATA%\Microsoft\Windows\SendTo\CAB.bat" >nul 2>nul
ping -n 6 localhost >nul &title cmd.exe &exit /b
:CabExtract %1:[.cab or .xx_]
echo %1 &pushd "%~dp1" &mkdir "%~n1" >nul 2>nul &expand -R "%~1" -F:* "%~n1" &popd &goto :eof
:CabFile %1:[filename]
echo %1 &pushd "%~dp1" &makecab /D CompressionType=LZX /D CompressionLevel=7 /D CompressionMemory=21 "%~nx1" "%~n1.cab" &goto :eof   
:CabDir %1:[directory]
dir /a:-D/b/s "%~1"
set "ddf="%temp%\ddf""
echo/.New Cabinet>%ddf%
echo/.set Cabinet=ON>>%ddf%
echo/.set CabinetFileCountThreshold=0;>>%ddf%
echo/.set Compress=ON>>%ddf%
echo/.set CompressionType=LZX>>%ddf%
echo/.set CompressionLevel=7;>>%ddf%
echo/.set CompressionMemory=21;>>%ddf%
echo/.set FolderFileCountThreshold=0;>>%ddf%
echo/.set FolderSizeThreshold=0;>>%ddf%
echo/.set GenerateInf=OFF>>%ddf%
echo/.set InfFileName=nul>>%ddf%
echo/.set MaxCabinetSize=0;>>%ddf%
echo/.set MaxDiskFileCount=0;>>%ddf%
echo/.set MaxDiskSize=0;>>%ddf%
echo/.set MaxErrors=1;>>%ddf%
echo/.set RptFileName=nul>>%ddf%
echo/.set UniqueFiles=ON>>%ddf%
setlocal enabledelayedexpansion
pushd "%~dp1"
for /f "tokens=* delims=" %%D in ('dir /a:-D/b/s "%~1"') do (
 set "DestinationDir=%%~dpD" &set "DestinationDir=!DestinationDir:%~1=!" &set "DestinationDir=!DestinationDir:~0,-1!"
 echo/.Set DestinationDir=!DestinationDir!;>>%ddf%
 echo/"%%~fD"  /inf=no;>>%ddf%
)
makecab /F %ddf% /D DiskDirectory1="" /D CabinetNameTemplate=%~nx1.cab &endlocal &popd &del /q /f %ddf% &goto :eof

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2015/01/20/1ce7a06a346c12452becdbf0726f50db.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com