neko.zip: Zip and Tar Gz archives
Note: If you want a cross platform zip solution, you should use the haxe format library (http://lib.haxe.org/p/format). More information about basic usage here: format.zip: Basic usage
Introduction
This tutorial demonstrates how to use zip and tar files in Haxe/Neko. The neko.zip
package can be used to read from and write to compressed archives. The important sections in the API are neko.zip.Reader
, neko.zip.Writer
, and neko.zip.ZipEntry
.
Input
The program operates on an existing zip and tar gz file. The program should work on any valid zip and tar gz files, but since the example outputs the files contents to the screen it would be best to create small example files for it to use. Create a directory named "data" in the current directory. Create a text file named "file1.txt" containing "this is a file" in the "data" directory. Then create a text file named "file2.txt" containing "this is another file" also in the "data" directory.
The directory tree should look like this:
data/ file1.txt file2.txt
Use any zip program to create a zip archive of the "data" directory named "data.zip." Also create a tar gz archive of it named "data.tgz." Windows users without a "tar" program can run this tutorial by commenting out the three lines of main
that calls readTar
and outputs its content.
Pre/Post Conditions
In order to run the example program, you must have "data.zip" and "data.tgz" in the current directory. The program will create a file named "data2.zip" in the same directory. Multiple runs will overwrite "data2.zip."
Walkthrough
In this example we will:
- read a zip file, output its contents
- read a tar gz file, output its contents
- write the contents of the tar gz file to a new zip file
- read the new zip file, output its contents
Code
The code is separated into several functions. We will go over each in detail.
Main
The main function makes several function calls that basically match the walkthrough. Note that data structures returned from reading zip or tar archives (archiveData
in the code below) can be used interchangeably.
public static function main() { var archiveData; archiveData = readZip("data.zip"); neko.Lib.println("\nzip files: "); printFiles(archiveData); archiveData = readTar("data.tgz"); neko.Lib.println("\ntar files: "); printFiles(archiveData); neko.Lib.println("\nwriting zip"); writeZip(archiveData, "data2.zip"); neko.Lib.println("done"); neko.Lib.println("\nreading new zip"); archiveData = readZip("data2.zip"); neko.Lib.println("zip files: "); printFiles(archiveData); }
Read Zip
The readZip
function opens the zip file, reads it into a data structure, closes it, then returns the data structure.
private static function readZip(fname) { var fin = neko.io.File.read(fname, true); var archiveData = neko.zip.Reader.readZip(fin); fin.close(); return archiveData; }
Read Tar
The readTar
is nearly the same as readZip
, except that it uses a different method from the neko.zip.Reader
class. The second argument of the readTar
method indicates that the input file is gzipped since its value is true
.
private static function readTar(fname) { var fin = neko.io.File.read(fname, true); var archiveData = neko.zip.Reader.readTar(fin, true); fin.close(); return archiveData; }
Print Files
This function outputs the file name and content for each entry read from the input file. A file's content is compressed if its compressed
field is set to true
. We decompress compressed data before outputting it.
private static function printFiles(archiveData : List<neko.zip.ZipEntry>) { for( ii in archiveData ) { var content = (ii.compressed) ? neko.zip.Reader.unzip(ii) : ii.data; neko.Lib.println(" " + ii.fileName + ": " + content); } }
Write Zip
The top section of this function does two things:
- it decompresses compressed data since the data passed into neko.zip.Writer.writeZip
should not already be compressed
- it removes unwanted fields of neko.zip.ZipEntry
The bottom section writes the output file. The third argument of neko.zip.Writer.writeZip
is the compression level. A value of -1
means average compression
.
private static function writeZip(archiveData : List<neko.zip.ZipEntry>, fname) { // remove unneeded fields of ZipEntry var convert = function(ii:neko.zip.ZipEntry) { var content = (ii.compressed) ? neko.zip.Reader.unzip(ii) : ii.data; return { fileTime:ii.fileTime, fileName:ii.fileName, data:content }; } var dataToWrite = Lambda.map(archiveData, convert); var fout = neko.io.File.write(fname, true); neko.zip.Writer.writeZip(fout, dataToWrite, -1); fout.close(); }
Full Program
neko.zip.Reader
must be imported since it defines the neko.zip.ZipEntry
type.
import neko.zip.Reader; import neko.zip.Writer; class ZipEx { public static function main() { var archiveData; archiveData = readZip("data.zip"); neko.Lib.println("\nzip files: "); printFiles(archiveData); archiveData = readTar("data.tgz"); neko.Lib.println("\ntar files: "); printFiles(archiveData); neko.Lib.println("\nwriting zip"); writeZip(archiveData, "data2.zip"); neko.Lib.println("done"); neko.Lib.println("\nreading new zip"); archiveData = readZip("data2.zip"); neko.Lib.println("zip files: "); printFiles(archiveData); } // read zip file private static function readZip(fname) { var fin = neko.io.File.read(fname, true); var archiveData = neko.zip.Reader.readZip(fin); fin.close(); return archiveData; } // read tar gz file private static function readTar(fname) { var fin = neko.io.File.read(fname, true); var archiveData = neko.zip.Reader.readTar(fin, true); fin.close(); return archiveData; } // output data read from archive to screen private static function printFiles(archiveData : List<neko.zip.ZipEntry>) { for( ii in archiveData ) { var content = (ii.compressed) ? neko.zip.Reader.unzip(ii) : ii.data; neko.Lib.println(" " + ii.fileName + ": " + content); } } // write data to zip file private static function writeZip(archiveData : List<neko.zip.ZipEntry>, fname) { // remove unneeded fields of ZipEntry var convert = function(ii:neko.zip.ZipEntry) { var content = (ii.compressed) ? neko.zip.Reader.unzip(ii) : ii.data; return { fileTime:ii.fileTime, fileName:ii.fileName, data:content }; } var dataToWrite = Lambda.map(archiveData, convert); var fout = neko.io.File.write(fname, true); neko.zip.Writer.writeZip(fout, dataToWrite, -1); fout.close(); } }
Compile and run with:
haxe -neko zip.n -main ZipEx.hx neko zip.n
The output should be:
zip files: data/file1.txt: this is a file data/file2.txt: this is another file data/: tar files: data/: data/file1.txt: this is a file data/file2.txt: this is another file writing zip done reading new zip zip files: data/: data/file1.txt: this is a file data/file2.txt: this is another file