2015-01-20 18 views
34

Ich kenne die ähnliche Frage wurde hier sehr gefragt, aber ich bin nicht vollständig mit den Antworten zufrieden (und sogar mit den Fragen).Wie kann ich Dateien und Ordner mit Batch-Dateien komprimieren (/ zippen) und dekomprimieren (/ entpacken), ohne externe Tools zu verwenden?

Das Hauptziel ist die Kompatibilität - es sollte für eine breite Palette von Windows-Maschinen (einschließlich XP, Vista, Win2003 - die zusammen hält immer noch etwa 20% der Windows-Anteil) und produzierte Dateien sollte unter Unix/Mac-Maschinen (so sind Standard-Archivierungs-/Komprimierungsformate vorzuziehen).

Was sind die Optionen:

  1. Erstellen eines Batches, die einige Zip-Algorithmus implementiert. Anscheinend ist möglich - aber nur mit einzelnen Dateien und die Verwendung CertUtil für binäre Verarbeitung (einige Maschinen nicht über CertUtil standardmäßig und ist nicht möglich, auf WinXP Home Edition installiert werden)
  2. Mit shell.application durch WSH.The besten Option nach zu me.It ermöglicht ganze Verzeichnisse zu zippen und wieder verwendbar ist auf jedem Windows-Rechner
  3. Makecab - trotz seiner Kompression ist nicht so tragbar sein auf jedem Windows machine.Some externe Programme wie 7zip sind in der Lage zu extrahieren. CAB-Inhalt, aber es wird nicht so sein Conven Wenn Dateien unter Unix/Mac verwendet werden müssen, und das Komprimieren einer einzelnen Datei ziemlich einfach ist, erfordert die Beibehaltung der Verzeichnisstruktur von ein wenig mehr Aufwand.
  4. Mit .NET Framework - nicht so gute Option.Form .NET 2.0 gibt es GZipStream, aber es ermöglicht nur die Komprimierung von einzelnen Dateien. .NET 4.5 hat Zip-Funktionen, aber es wird nicht unter Vista und XP unterstützt. Und noch mehr - .NET ist nicht standardmäßig auf XP und Win2003 installiert, aber , da es sehr wahrscheinlich ist, .NET 2.0 bis zu 4.0 zu haben erhebliche opion.
  5. Powershell - da es auf .NET beruht, hat es die gleichen Fähigkeiten. Es ist nicht standardmäßig auf XP, 2003 und Vista installiert, so werde ich es überspringen.
+2

Hat Ihre 'Shell.Application' Methode die [2GB Größenbeschränkung] (http://www.naterice.com/blog/template_permalink.asp?id=64)? Beachten Sie auch, dass das ZIP64-Format nur für 'Shell.Application' in [Vista oder neuer] (http://en.wikipedia.org/wiki/Zip_ (Dateiformat) # ZIP64) unterstützt wird. –

+0

@DavidRuhmann - Die größte Datei, die ich getestet habe, war 1,5 GB. Höchstwahrscheinlich ist die Größe begrenzt. Testen Sie es und aktualisieren Sie es. – npocmaka

+0

Ich habe gerade [meine »Shell.Application« -Lösung] (http://stackoverflow.com/a/27279354/1683264) getestet, die erfolgreich das Verzeichnis mit meiner virtuellen XP-Modus-Festplatte, die etwa 6,2 Gigs umfasst, komprimiert. Es komprimierte auf 2,44 Gigs. Ich habe dann IZArc zum Entpacken verwendet, und alle Inhalte wurden ohne Fehler mit Größen identisch mit den Originalen extrahiert. Dies ist auf Win7 x64. – rojo

Antwort

50

Und hier sind die Antwort (en):

1.Using "reine" Batch-Skript, zip/unzip Datei.

Es ist möglich, dank Frank Westlake ZIP.CMD und UNZIP.CMD (benötigt Admin-Berechtigungen und erfordert FSUTIL und CERTUTIL) .Für Win2003 und WinXP es 2003 Admin Tool Pack erfordert die CERTUTIL installieren. Seien Sie vorsichtig, da die ZIP.CMD-Syntax rückwärts ist:

ZIP.CMD destination.zip source.file 

Und es kann nur einzelne Dateien zippen.

2.Using Shell.Application

Ich habe einige Zeit damit verbracht eine einzelne jscript/Batch-Hybrid-Skript für die gemeinsame Nutzung zu erstellen, die Reißverschlüsse/dekomprimiert Dateien und Verzeichnisse (plus einige weitere Merkmale).Here's a link to it (es wurde zu groß, um in der Antwort zu posten). Kann direkt mit der Erweiterung .bat verwendet werden und erstellt keine temporären Dateien. Ich hoffe, die Hilfe Nachricht ist beschreibend genug, wie es verwendet werden kann.

Einige Beispiele:

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

einige bekannte Probleme bei zippen:

  • , wenn es auf dem Systemlaufwerk (in der Regel C :) das Skript verschiedene Fehler erzeugen könnte, meist nicht genug Platz ist der Skript hält an.Dies liegt an Shell.Application aktiv verwendet % TEMP% Ordner zum Komprimieren/Dekomprimieren der Daten.
  • Ordner und Dateien, die Unicode-Symbole in ihren Namen enthalten, können nicht vom Shell.Application-Objekt verarbeitet werden.
  • Max unterstützte Größe der produzierten Zip-Dateien um 8gb in Vista ist und über und um 2gb in XP/2003

Das Skript erkennt, wenn Fehlermeldung-up öffnet und stoppt die Ausführung und informiert für die möglichen Gründe. Im Moment habe ich keine Möglichkeit, den Text im Pop-up zu erkennen und den genauen Grund für den Fehler anzugeben.

3. Makecab.

Komprimieren einer Datei ist einfach - makecab file.txt "file.cab". Schließlich könnte MaxCabinetSize erhöht werden. Komprimieren eines Ordners erfordert eine Verwendung DestinationDir Direktive (mit relativen Pfaden) für jedes (Unter) Verzeichnis und die darin enthaltenen Dateien. Hier ist ein Skript:

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

Für Dekompression EXPAND cabfile -F:* . used.For Extraktion in Unix cabextract sein kann oder 7zip verwendet werden.

4. .NET und GZipStream

zog ich eine Jscript.net wie es eine ordentliche Hybridisierung mit .bat erlaubt (keine toxischen Ausgang und keine temporären Dateien) .Jscript erlauben keine Referenz von vorbei Objekt zu einer Funktion, so die einzige Weise, die ich gefunden habe, um es arbeiten zu lassen, ist by byte by byte lesen/schreiben (also nehme ich an, es ist nicht der schnellste Weg - wie gepuffertes Lesen/Schreiben kann getan werden?) Wieder kann nur mit Single verwendet werden Dateien.

@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); 
} 
+3

Definitiv die umfassendste Sammlung von Lösungen. – jsxt

+2

Es ist in der Tat eine große Sammlung von Lösungen. Ich mag am meisten die Lösung 2 mit 'zipjs.bat'. Aber ich habe eine Verbesserungsanfrage für 'zipjs.bat'. Bei __unzip__ einer ZIP-Datei hinterlässt es in '% TEMP%' die Unterverzeichnisse und Dateien, die temporär zum Extrahieren jeder Datei aus der ZIP-Datei verwendet werden. Es wäre gut, wenn diese Hybrid-Batch-Datei sie selbst löschen würde, siehe meine Antwort auf [Wie schreibe ich eine Batch-Datei, die eine Datei in einen neuen Ordner mit dem gleichen Namen entpacken kann?] (Http://stackoverflow.com/ a/31502536/3074564) – Mofi

+0

@Mofi - wird dies überprüfen. Ich erstelle keine Reißverschlüsse im temporären Ordner - so funktioniert die shell.application. Ich habe zwei weitere Anfragen bezüglich 'zipjs.bat' und hoffe, dass ich bald die Zeit habe, sie zu aktualisieren. – npocmaka

4

erstaunliche lösungen!

Die makecab-Lösung hat einige Probleme, daher ist hier eine feste Version, die das Problem bei der Verwendung von Verzeichnissen mit Leerzeichen löst.

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

CAB.bat [Eingabe] Ordner oder eine Datei: Pack | .cab oder. ??_: auspacken | none: Packung ein files Unterordner
auch einen CAB Eintrag der rechten Maustaste SendTo Menü für die einfache Handhabung
hinzufügen Da dies eine nahtlos beide Aufgaben der Fall ist, sollte man über die hässliche makecab bevorzugt werden - warum Hybrid-Skript verwenden, wenn Sie schreiben temp-Datei trotzdem?

@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