neko.zip: Zip and Tar Gz archives

You are viewing an old version of this entry, click here to see latest version.

Introduction

This tutorial demonstrates how to use zip and tar files in Haxe/Neko. The neko.zip can be used to read and write to compressed archives. The important methods are in neko.zip.Reader, neko.zip.Writer, and neko.zip.ZipEntry.

Input

The program operates on an existing zip and tar gz file. Since the example outputs the file contents to the screen it would be best to create an example file for it to use. Create a directory named "data" in the current directory. In the "data" directory, create a text file named "file1.txt" containing "this is a file." Now create a text file in the "data" directory named "file2.txt" containing "this is another file."

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

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'll 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 treated the same way.

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.

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 unzip 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 uncompresses 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

Note that neko.zip.Reader must be imported since it defines the neko.zip.ZipEntry type.

import neko.zip.Reader;

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

version #5872, modified 2009-04-29 23:10:30 by ianxm