it-swarm.com.de

Wie kann ich Dateien und Ordner mit Batch-Dateien komprimieren (/ zip) und dekomprimieren (/ dekomprimieren), ohne externe Tools zu verwenden?

Ich weiß, dass die ähnliche Frage hier oft gestellt wurde, aber ich bin mit den Antworten (und sogar mit den Fragen) nicht ganz zufrieden.

Das Hauptziel ist die Kompatibilität - es sollte für eine möglichst breite Palette von Windows-Computern (einschließlich XP, Vista, Win2003 - die zusammen immer noch rund 20% der Windows-Anteile ausmachen) anwendbar sein, und produzierte Dateien sollten auf Unix/Mac-Computern (also Standard) verwendbar sein Archivierungs-/Komprimierungsformate sind vorzuziehen.

Welche Optionen gibt es:

  1. Erstellen eines Stapels, der einen Zip-Algorithmus implementiert. Anscheinend ist dies möglich - aber nur mit einzelnen Dateien und unter Verwendung von CERTUTIL für die Binärverarbeitung (einige Computer verfügen nicht standardmäßig über CERTUTIL und können nicht unter WinXP Home Edition installiert werden).
  2. Verwenden von Shell.application durch WSH. Die beste Option für mich. Es ermöglicht das Komprimieren ganzer Verzeichnisse und kann auf jedem Windows-Computer verwendet werden
  3. Makecab - Obwohl die Komprimierung nicht so portabel ist, ist sie auf jedem Windows-Computer verfügbar. Einige externe Programme wie 7Zip sind in der Lage, CAB-Inhalte zu extrahieren, aber es ist nicht so praktisch, wenn Dateien verwendet werden müssen Unix/Mac.Und während das Komprimieren einer einzelnen Datei ziemlich einfach ist, erfordert das Beibehalten der Verzeichnisstruktur etwas mehr Aufwand.
  4. Mit .NET Framework - nicht so gute Option.Form .NET 2.0 gibt es GZipStream , aber es erlaubt nur die Komprimierung einzelner Dateien. .NET 4.5 verfügt über Zip-Funktionen, wird jedoch unter Vista und XP .Und noch mehr - .NET wird nicht standardmäßig unter XP und Win2003 installiert, aber Da es sehr wahrscheinlich ist, .NET 2.0 bis 4.0 zu haben, handelt es sich um eine beträchtliche Option.
  5. Powershell - da es auf .NET basiert, hat es die gleichen Funktionen. Es ist nicht standardmäßig auf XP, 2003 und Vista installiert, daher werde ich es überspringen.
41
npocmaka

Und hier sind die Antworten:

1.Mit "reinem" Batch-Skript die Datei komprimieren/entpacken.

Möglich ist dies dank Frank Westlakes Zip.CMD und UNZIP.CMD (benötigt Administratorrechte und erfordert FSUTIL und CERTUTIL). Für Win2003 und WinXP wird das 2003 Admin Tool Pack benötigt, mit dem CERTUTIL installiert wird. Seien Sie vorsichtig, da die Zip.CMD-Syntax rückwärts ist:

Zip.CMD destination.Zip source.file

Und es kann nur einzelne Dateien komprimieren.

2.Mit Shell.Application

Ich habe einige Zeit damit verbracht, ein einzelnes jscript/batch-Hybridskript für die allgemeine Verwendung zu erstellen, das Dateien und Verzeichnisse komprimiert/dekomprimiert (plus einige weitere Funktionen). Here's ein Link dazu (es wurde zu groß, um in der Antwort zu posten). Kann direkt mit seinem .bat Erweiterung und erstellt keine temporären Dateien. Ich hoffe, die Hilfemeldung beschreibt genug, wie sie 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 beim Zippen:

  • wenn nicht genügend Speicherplatz auf dem Systemlaufwerk vorhanden ist (normalerweise C :), kann das Skript verschiedene Fehler verursachen. In den meisten Fällen wird das Skript angehalten. Dies liegt daran, dass Shell.Application active uses - % TEMP% Ordner zum Komprimieren/Dekomprimieren der Daten.
  • Ordner und Dateien, deren Namen Unicode-Symbole enthalten, können vom Shell.Application-Objekt nicht verarbeitet werden.
  • Die maximal unterstützte Größe der produzierten Zip-Dateien beträgt in Vista und höher ca. 8 GB und in XP/2003 ca. 2 GB

Das Skript erkennt, ob eine Fehlermeldung angezeigt wird, bricht die Ausführung ab und informiert aus den möglichen Gründen. Im Moment habe ich keine Möglichkeit, den Text im Popup zu erkennen und den genauen Grund für den Fehler anzugeben.

. Makecab.

Eine Datei zu komprimieren ist einfach - makecab file.txt "file.cab". Eventuell kann MaxCabinetSize erhöht werden. Das Komprimieren eines Ordners erfordert die Verwendung der Direktive DestinationDir (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 ;;;;;

Zur Dekompression EXPAND cabfile -F:* . kann verwendet werden. Für die Extraktion in Unix kann cabextract oder 7Zip verwendet werden.

4. .NET und GZipStream

Ich bevorzuge ein Jscript.net, da es eine saubere Hybridisierung mit .bat ermöglicht (keine toxische Ausgabe und keine temporären Dateien) .Jscript erlaubt es nicht, einen Verweis auf ein Objekt an eine Funktion zu übergeben Dateien byteweise lesen/schreiben (also ist es wohl nicht der schnellste Weg - wie kann gepuffert gelesen/geschrieben werden?) Auch hier kann nur mit einzelnen Dateien gearbeitet werden.

@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);
}
57
npocmaka

erstaunliche Lösungen!

Die makecab-Lösung weist einige Probleme auf, daher gibt es hier eine feste Version, die das Problem bei der Verwendung von Verzeichnissen mit Leerzeichen behebt.

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

CAB.bat [Eingabe] Ordner oder Datei: pack | .cab oder. ?? _: auspacken | none: packe einen files Unterordner
Fügt außerdem einen Eintrag CAB zum Rechtsklick auf das SendTo-Menü hinzu, um die Handhabung zu vereinfachen
Da dieses Programm beide Aufgaben nahtlos erledigt, sollte es dem hässlichen Makecab vorgezogen werden - warum Hybrid-Skript verwenden, wenn Sie trotzdem in temporäre Dateien schreiben?

@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
2
AveYo