.net 如何在不使用任何外部工具的情况下使用批处理文件压缩 (/ zip ) 和解压缩 (/ unzip ) 文件和文件夹?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28043589/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I compress (/ zip ) and uncompress (/ unzip ) files and folders with batch file without using any external tools?
提问by npocmaka
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 :
有哪些选项:
- 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)
- Using shell.applicationthrough WSH.The best option according to me.It allows zipping whole directories and is usable on every windows machine
- 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.
- Using .NET Framework - not so good option.Form .NET 2.0 there is GZipStreambut 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.
- 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.
- 创建一个实现一些 zip 算法的批处理。显然这是可能的 - 但仅限于单个文件并使用 CERTUTIL 进行二进制处理(某些机器默认没有 CERTUTIL,并且不可能安装在 WinXP Home Edition 上)
- 通过 WSH使用shell.application。根据我的最佳选择。它允许压缩整个目录并且可以在每台 Windows 机器上使用
- Makecab- 尽管它的压缩不是那么便携,但它在每台 Windows 机器上都可用。一些外部程序,如 7zip 能够提取 .CAB 内容,但是当需要在 Unix/Mac 上使用文件时,它会不太方便。并且在压缩时单个文件非常简单,保留目录结构需要更多的努力。
- 使用 .NET Framework - 不是很好的选择。Form .NET 2.0 有 GZipStream但它只允许压缩单个文件。.NET 4.5 具有 Zip 功能,但它在 Vista 和 XP 上不受支持。更重要的是 - XP 和 Win2003 上默认不安装 .NET,但因为很有可能将 .NET 2.0 升级到 4.0,这是一个相当不错的选择.
- Powershell - 因为它依赖于 .NET,所以它具有相同的功能。默认情况下它没有安装在 XP、2003 和 Vista 上,所以我将跳过它。
回答by npocmaka
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.CMDand UNZIP.CMD(needs admin permissions and requires FSUTILand CERTUTIL) .For Win2003 and WinXP it will require 2003 Admin Tool Packwhich will install CERTUTIL. Be careful as ZIP.CMD syntax is backward :
这是可能的感谢Frank西湖的ZIP.CMD和UNZIP.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 .batextension 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:
压缩过程中的一些已知问题:
- 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.Applicationactively uses %TEMP%folder to compress/decompress the data.
- Folders and files that contain unicode symbols in their names cannot be handled by Shell.Application object.
- Max supported size of produced zip files is around 8gb in Vista and above and around 2gb in XP/2003
- 如果系统驱动器(通常是 C:)上没有足够的空间,脚本可能会产生各种错误,大多数情况下脚本会停止。这是由于Shell.Application主动使用%TEMP%文件夹来压缩/解压缩数据。
- Shell.Application 对象无法处理名称中包含 unicode 符号的文件夹和文件。
- 生成的 zip 文件的最大支持大小在 Vista 及更高版本中约为 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.出租车。
Compressing a file is easy - makecab file.txt "file.cab". Eventually MaxCabinetSizecould be increased.
Compressing a folder requires a usage DestinationDirdirective (with relative paths) for every (sub)directory and the files within .
Here's a script:
压缩文件很容易 - 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 ;;;;;
Example usage:
用法示例:
call cabDir.bat ./myDir compressedDir.cab
For decompression EXPAND cabfile -F:* .can be used.For extraction in Unix cabextractor 7zipcan be used.
对于解压EXPAND 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);
}
Example usage:
用法示例:
//zip
call netzip.bat -c my.file my.zip
//unzip
call netzip.bat -u my.zip my.file
5. TAR (only for the newest windows builds)
5. TAR(仅适用于最新的 Windows 版本)
With the latest builds of windows 10 now we have TARcommand ,though it's not the most backward compatible option:
使用最新版本的 Windows 10 现在我们有了TAR命令,尽管它不是最向后兼容的选项:
//compress directory
tar -cvf archive.tar c:\my_dir
//extract to dir
tar -xvf archive.tar.gz -C c:\data
回答by Ilde
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 ;;;;;
回答by AveYo
CAB.bat[input] folder or file : pack | .cab or .??_ : unpack | none : pack a filessubfolder
Will also add a CABentry 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?
CAB.bat[输入] 文件夹或文件:pack | .cab 或 .??_ : 解压 | none : 打包一个files子文件夹
还将添加一个CAB条目到右键单击 SendTo 菜单以便于处理
因为这个可以无缝地完成这两个任务,所以它应该比丑陋的 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

