Application File Format

Motivation

Suppose you're writing a plug-in for the next generation application which shall use an archive file format with a custom file suffix (extension) as a persistent container for some application data, e.g. a text document.

Then, wouldn't it be nice if you wouldn't need to worry about how to read or write archive files using cumbersome archive type specific APIs?

Accessing Application File Formats

Thanks to the TrueZIP File* module, here's your relief: The TFile, TFileInputStream and TFileOutputStream classes can read and write entries within an archive file as if they were plain files in regular directories in the file system.

First, you need to register your custom application file format suffix with an instance of an archive driver class like this:

TConfig.get().setArchiveDetector(
    new TArchiveDetector(
        "foo|bar",
        new JarDriver(IOPoolLocator.SINGLETON)));

Once this has been called, any new TFile object will recognize the file suffixes foo and bar, whereby case is ignored, and assume the JAR file format to read or write these files.

Note that TrueZIP automatically recognizes false positive archive files, so it cannot get confused by files with arbitrary content which accidently use the suffix of your custom application file format.

Please also note the usage of the class JarDriver for accessing the JAR file format. The JAR file format is typically the best choice for custom application file formats because it supports compression, fast access and UTF-8 encoded entry names for maximum interoperability. In particular, the last point makes it superior to the ZIP file format.

Now you can easily create or overwrite an entry in your custom application file format like this:

OutputStream out = new TFileOutputStream("file.foo/contents.xml");
try {
    ...;
} finally {
    out.close(); // ALWAYS close the resource here!
}

Alternatively, you could use a TFileWriter.

This is how you could read the entry again:

InputStream in = new TFileInputStream("file.foo/contents.xml");
try {
    ...;
} finally {
    in.close(); // ALWAYS close the resource here!
}

Alternatively, you could use a TFileReader.

And finally, to delete a virtual directory tree - in this case your custom application file - you could use this:

new TFile("file.foo").rm_r();

Note that calling the method rm_r() is required to recursively delete the application file because the TFile object refers to a virtual directory, which cannot get deleted using similar methods like delete() or rm() unless it's empty.

Committing Changes / Cleaning Up

If your application has created or changed one or more archive files, then these changes need to get committed sometime. Even if your application has done read-only acess to the virtual file system, some temporary files may have been created to speed up random access - this dependends on the driver implementation.

If your application is only short-running, then there is actually nothing to do because the TrueZIP Kernel automatically registers and de-registers a JVM shutdown hook which will commit all changes when its run. Note that shutdown hooks are run even if the application terminates due to a Throwable.

However, if your application is long running or wants to handle any exceptions, then you may want to manually call this operation - here's how to do this:

TVFS.umount();

As a side effect, once this operation succeeded, third parties (e.g. other processes) can safely access the processed archive files until the next time your application starts to operate on them again.

Performance Considerations

Take care not to call TVFS.umount() in a loop which updates the same set of archive files because this would result in poor performance in the order of O(n*n) instead of just O(n), where n is the total number of archive entries.

For more information, please refer to the Javadoc for TVFS.umount().