Creating a Zip File on Windows (Xp/2003) in C/C++

Creating a ZIP file on Windows (XP/2003) in C/C++

EDIT: This answer is old, but I cannot delete it because it was accepted. See the next one

https://stackoverflow.com/a/121720/3937

----- ORIGINAL ANSWER -----

There is sample code to do that here

[EDIT: Link is now broken]

http://www.eggheadcafe.com/software/aspnet/31056644/using-shfileoperation-to.aspx

Make sure you read about how to handle monitoring for the thread to complete.

Edit: From the comments, this code only works on existing zip file, but @Simon provided this code to create a blank zip file

FILE* f = fopen("path", "wb");
fwrite("\x50\x4B\x05\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 22, 1, f);
fclose(f);

Creating an empty .zip file in C++

The stated problem, that no file is created, is impossible to answer with the information given. It is most likely due to an invalid file path. However, the OP states in a comment that the path in his example is not the real code.


EDIT: the hex string example that I cited originally was wrong, I just tested.

This code works:

#include <stdio.h>

auto main() -> int
{
FILE* f = fopen("foo.zip", "wb");
//fwrite( "\x80\x75\x05\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 22, 1, f );
fwrite( "\x50\x4B\x05\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 22, 1, f );
fclose(f);
}

Harumph, one cannot even trust Stack Overflow comments. Not to mention accepted answers.


Original text:

Assuming that the OP now has edited the code so that the part below is the real code, then this constant

{80, 75, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

is not identical to

"\x80\x75\x05\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"

Can the OP spot the relevant difference?

Further, given that, can the OP infer anything about his source of information?

My example from a comment elsewhere.

Creating a compressed (or zipped) folder

Have a look at the following links:

http://www.rondebruin.nl/windowsxpzip.htm

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1383147&SiteID=1

Stripping the important parts from the first link example may prove to be sufficient.

Sub NewZip(sPath)
'Create empty Zip File
'Changed by keepITcool Dec-12-2005
If Len(Dir(sPath)) > 0 Then Kill sPath
Open sPath For Output As #1
Print #1, Chr$(80) & Chr$(75) & Chr$(5) & Chr$(6) & String(18, 0)
Close #1
End Sub

Function Split97(sStr As Variant, sdelim As String) As Variant
'Tom Ogilvy
Split97 = Evaluate("{""" & _
Application.Substitute(sStr, sdelim, """,""") & """}")
End Function

Sub Zip_File_Or_Files()
Dim strDate As String, DefPath As String, sFName As String
Dim oApp As Object, iCtr As Long, I As Integer
Dim FName, vArr, FileNameZip

DefPath = Application.DefaultFilePath
If Right(DefPath, 1) <> "\" Then
DefPath = DefPath & "\"
End If

strDate = Format(Now, " dd-mmm-yy h-mm-ss")
FileNameZip = DefPath & "MyFilesZip " & strDate & ".zip"

'Browse to the file(s), use the Ctrl key to select more files
FName = Application.GetOpenFilename(filefilter:="Excel Files (*.xl*), *.xl*", _
MultiSelect:=True, Title:="Select the files you want to zip")
If IsArray(FName) = False Then
'do nothing
Else
'Create empty Zip File
NewZip (FileNameZip)
Set oApp = CreateObject("Shell.Application")
I = 0
For iCtr = LBound(FName) To UBound(FName)
vArr = Split97(FName(iCtr), "\")
sFName = vArr(UBound(vArr))
If bIsBookOpen(sFName) Then
MsgBox "You can't zip a file that is open!" & vbLf & _
"Please close it and try again: " & FName(iCtr)
Else
'Copy the file to the compressed folder
I = I + 1
oApp.Namespace(FileNameZip).CopyHere FName(iCtr)

'Keep script waiting until Compressing is done
On Error Resume Next
Do Until oApp.Namespace(FileNameZip).items.Count = I
Application.Wait (Now + TimeValue("0:00:01"))
Loop
On Error GoTo 0
End If
Next iCtr

MsgBox "You find the zipfile here: " & FileNameZip
End If
End Sub

How to create a password protected ZIP file in Windows using C?

You can use minizip library on Windows. It can be compiled via CMake.

This is how you can use it to create a password-protected zip file:

#include "mz.h"
#include "mz_os.h"
#include "mz_strm.h"
#include "mz_strm_buf.h"
#include "mz_strm_split.h"
#include "mz_zip.h"
#include "mz_zip_rw.h"
#include <stdio.h>

int main() {
void *writer = NULL;
int32_t err = MZ_OK;

mz_zip_writer_create(&writer);
mz_zip_writer_set_password(writer, "mypassword");
mz_zip_writer_set_compress_method(writer, MZ_COMPRESS_METHOD_DEFLATE);
mz_zip_writer_set_compress_level(writer, MZ_COMPRESS_LEVEL_DEFAULT);
err = mz_zip_writer_open_file(writer, "output.zip", 0, 0);
if (err != MZ_OK) {
printf("Could not open zip file for writing.");
return 1;
}
err = mz_zip_writer_add_path(writer, "text1.txt", NULL, 0, 0);
if (err != MZ_OK) {
printf("Failed to add file to the archive.");
}
mz_zip_writer_close(writer);
mz_zip_writer_delete(&writer);
return 0;
}

This code will create a output.zip file with a password-protected file text1.txt.

For more information and uses refer to the minizip.c sample file.

I hope it helps.

How can you zip or unzip from the script using ONLY Windows' built-in capabilities?

Back in 2013, that was not possible. Microsoft didn't provide any executable for this.

See this link for some VBS way to do this.
https://superuser.com/questions/201371/create-zip-folder-from-the-command-line-windows

From Windows 8 on, .NET Framework 4.5 is installed by default, with System.IO.Compression.ZipArchive and PowerShell available, one can write scripts to achieve this, see
https://stackoverflow.com/a/26843122/71312

Simplest way to unpack ZIP from C++?

Have a look at Rich Geldreich's miniz. It's not winapi specific but it's so an easy way to add ZIP support to your application.

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

And here are the answer(s):

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

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 :

ZIP.CMD destination.zip source.file

And it can zip only single files.

2. Using 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.

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.Application actively 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

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

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:

;@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 cabextract or 7zip can be used.

4. .NET and 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.

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

With the latest builds of windows 10 now we have TAR command ,though it's not the most backward compatible option:

//compress directory
tar -cvf archive.tar c:\my_dir
//extract to dir
tar -xvf archive.tar.gz -C c:\data
//compres to zip format
tar -caf archive.zip c:\my_dir


Related Topics



Leave a reply



Submit