Jak skompresować (/ zip) i rozpakować (/rozpakować) pliki i foldery za pomocą pliku wsadowego bez użycia zewnętrznych narzędzi?

Wiem, że podobne pytania zadawano tu często, ale nie jestem do końca zadowolony z odpowiedzi (a nawet z pytań).

Głównym celem jest kompatybilność - powinna mieć zastosowanie do jak najszerszej gamy maszyn z systemem Windows (w tym XP, Vista i Server 2003 - które razem nadal posiadają około 20% udziału w systemie Windows) i produkowane pliki powinny być użyteczne na komputerach Unix / Mac (więc standardowe formaty archiwizacji/kompresji są preferowane).

jakie są opcje:

  1. Tworzenie wsadu implementującego algorytm zip. Prawdopodobnie jest to możliwe - ale tylko z pojedynczymi plikami i używaniem CERTUTIL do przetwarzania binarnego (niektóre maszyny nie mają CERTUTIL domyślnie i nie jest możliwe zainstalowanie w Windows XP Home Edition) {]}
  2. używając powłoki.zastosowanie do WSH . Według mnie jest to najlepsza opcja. Pozwala na zamocowanie całych katalogów i jest możliwość użycia na każdym komputerze z systemem Windows
  3. Makecab - pomimo swojej kompresji nie jest tak przenośny, jest dostępny na każdym komputerze z systemem windows. Niektóre programy zewnętrzne, takie jak 7-Zip, są w stanie wyodrębnić .Zawartość CAB, ale nie będzie to tak wygodne, gdy pliki muszą być używane na Unix/Mac. I chociaż kompresja pojedynczego pliku jest dość prosta, zachowanie struktury katalogów wymaga trochę więcej wysiłku.
  4. Korzystanie z. NET Framework-niezbyt dobra opcja. Z. NET 2.0 tam jest GZipStream , ale pozwala na kompresję tylko pojedynczych plików. . NET 4.5 ma możliwości Zip, ale nie jest obsługiwany na Vista i XP. I jeszcze więcej -. NET nie jest instalowany domyślnie na XP i Server 2003, ale ponieważ jest wysoce prawdopodobne, że ma. NET 2.0 do 4.0, jest to znaczna opcja.
  5. PowerShell-ponieważ opiera się na.Net ma takie same możliwości. Nie jest zainstalowany domyślnie na XP, Server 2003 i Vista, więc pominę go.
Author: Peter Mortensen, 2015-01-20

4 answers

A oto odpowiedź (y):

1. Używanie" czystego " skryptu wsadowego do pliku zip/rozpakuj.

To możliwe dzięki ZIP Franka Westlake ' a.CMD i rozpakować.CMD(wymaga uprawnień administratora i wymaga FSUTIL i CERTUTIL).Dla Win2003 i WinXP będzie wymagał 2003 Admin Tool Pack który zainstaluje CERTUTIL. Bądź ostrożny jak ZIP.Składnia CMD jest wsteczna:
ZIP.CMD destination.zip source.file

I może zip tylko pojedyncze pliki.

2. Za pomocą Shell.Zastosowanie

Spędziłem trochę czasu na stworzeniu jednego hybrydowego skryptu JScript/batch do wspólnego użytku, który zamyka / rozpakowuje pliki i katalogi (plus kilka dodatkowych funkcji).oto link do niego (stał się zbyt duży, aby umieścić w odpowiedzi). Może być używany bezpośrednio z rozszerzeniem .bat i nie tworzy żadnych plików tymczasowych. Mam nadzieję, że komunikat pomocy jest wystarczająco opisowy, jak można go wykorzystać.

Niektóre przykłady:

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

Niektóre znane problemy podczas zapinania:

  • jeśli nie ma wystarczającej ilości miejsca na dysku systemowym (Zwykle C:) skrypt może powodować różne błędy , najczęściej skrypt się zatrzymuje.Jest to spowodowane Shell.Aplikacja aktywnie używa folderu %TEMP% do kompresji/dekompresji danych.
  • foldery i pliki zawierające symbole unicode w swoich nazwach nie mogą być obsługiwane przez powłokę.Obiekt aplikacji.
  • maksymalny obsługiwany rozmiar produkowanych plików zip to około 8gb w Vista i nowszych oraz około 2gb W XP / 2003

Skrypt wykrywa, czy wyskakuje komunikat o błędzie i zatrzymuje wykonanie i informuje o możliwej reasons.At w tej chwili nie mam możliwości wykrycia tekstu wewnątrz wyskakującego i podania dokładnej przyczyny awarii.

3. Makecab

Kompresja pliku jest łatwa - makecab file.txt "file.cab" . Ostatecznie MaxCabinetSize może być zwiększona. Kompresowanie folderu wymaga dyrektywy usage DestinationDir (z ścieżki względne) dla każdego (pod)katalogu i plików wewnątrz . Oto skrypt:

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

Przykładowe użycie:

call cabDir.bat ./myDir compressedDir.cab

Do dekompresji EXPAND cabfile -F:* . mogą być użyte.Do ekstrakcji w systemie Unix można użyć cabextractlub 7zip.

4. . NET i GZipStream

Wolałem Jscript.net ponieważ pozwala na zgrabną hybrydyzację z .bat (brak toksycznych danych wyjściowych i brak plików temp).Jscript nie pozwala na przekazywanie referencji obiektu do funkcji, więc jedynym sposobem, w jaki znalazłem spraw, aby działało to przez odczyt / zapis plików bajt po bajcie (więc przypuszczam, że nie jest to najszybszy sposób - jak można wykonać buforowany Odczyt / Zapis?) Ponownie może być używany tylko z pojedynczymi plikami.

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

Przykładowe użycie:

//zip
call netzip.bat -c my.file my.zip
//unzip
call netzip.bat -u my.zip my.file

5. TAR (tylko dla najnowszych wersji Windows)

Z najnowszymi kompilacjami windows 10 mamy teraz polecenie TAR , choć nie jest to najbardziej kompatybilna wstecz opcja:

//compress directory
tar -cvf archive.tar c:\my_dir
//extract to dir
tar -xvf archive.tar.gz -C c:\data
 66
Author: npocmaka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-21 02:08:40

Niesamowite rozwiązania!

Rozwiązanie makecab ma pewne problemy, więc oto poprawiona wersja, która rozwiązuje problem podczas korzystania z katalogów z pustymi spacjami.

;@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 ;;;;;
 5
Author: Ilde,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-27 19:26:54

Taksówka.bat [input] folder lub plik: pack/.taksówka lub .??_ : unpack / none: pack a files subfolder
Dodaje również wpis CAB do menu SendTo, aby ułatwić obsługę
Ponieważ ten wykonuje oba zadania bezproblemowo, powinien być preferowany niż brzydki makecab - po co używać skryptu hybrydowego, jeśli i tak piszesz do pliku tymczasowego?

@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
Author: AveYo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-17 20:00:21

Niektóre przykłady z powershell używając Compress-Archive i Expand-Archive :

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

Tak jak w aktualnie obsługiwanych wersjach systemu windows te cmd-lets są instalowane domyślnie.

Inne sposoby z 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""");"
 0
Author: npocmaka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-02-08 08:58:28