Feature Spotlight: Bulk Copying Of Files And Directories

If you are a TrueZIP user, you probably know that TrueZIP 6 provides various methods for bulk copying of files and directories. This article features the new methods for bulk copying in TrueZIP 7.

The methods of the File/TFile class in the File* API provide the following advantages compared to the well known, but naive read-then-write-data-loop implementation:

  • Transparent access to source or destination archive files as if they were just plain directories.
  • Recursive copying of (virtual) directory trees.
  • Superior performance by applying pooled reader threads and buffers.
  • No need to inflate the data when reading it then deflate it again when writing a copy of an entry from a compressed archive file to another compressed archive file of the same type.

However, in TrueZIP 6 these methods just return a boolean value to indicate success or failure which makes failure analysis almost impossible. My excuse for this admittedly bad design is that these methods were modeled after their companions like delete() or renameTo(*) in the class java.io.File.

Now in TrueZIP 7, the boolean methods have been deprecated and reimplemented to call new public static void methods which provide the same advantages, but throw an IOException on failure. So instead of writing…

TFile src = new TFile("directory");
TFile dst = new TFile("archive.zip");
if (!src.archiveCopyAllTo(dst)) // deprecated
    throw new IOException("Oh s**t - you're doomed!");

now you write…

TFile src = new TFile("directory");
TFile dst = new TFile("archive.zip");
src.cp_rp(dst); // throws IOException on failure

The method call cp_rp(src, dst) is modeled after the Unix command cp -rp .... In this case, it recursively copies the directory directory to the archive file i.e. virtual directory archive.zip and provides a best effort to copy the file attributes. However, currently only the last modification time gets copied due to I/O limitations in JSE 6.

Note that in order to prevent ambiguities, TrueZIP does not provide auto-completion for path names and mixing files and directories as the source and destination parameters is not supported, too! So in order to copy an individual file to an archive file, you need to write something like this:

TFile src = new TFile("file");
TFile dst = new TFile("archive.zip/file"); // must be the complete path name of a file!
src.cp_rp(dst); // creates archive.zip if it doesn't exist!

Note that archive.zip does not need to exist prior to this call unless TFile.setLenient(false) has been called before. This feature is limited to archive file names and any directory entry names within archive file names, i.e. you cannot automatically create non-existent directories outside of an archive file this way.

The class TFile provides some constructors and methods to aid you in the task of constructing complete path names. With their help, you can easily mimic the semantics of the cp -rp ... command like this:

public static void main(String[] args) throws IOException {
    TFile src = new TFile(args[0]);
    TFile dst = new TFile(args[1]);
    if (dst.isArchive() || dst.isDirectory())
        dst = new TFile(dst, src.getName());
    src.cp_rp(dst);
}

In this example, src may refer to a file or directory - it doesn’t matter because the copy method works recursively.

The base name of src gets appended to dst if either dst names an archive file or refers to a directory or archive file, i.e. a virtual directory. Note that the method isArchive() scans only the path name but does not access the file system for its test while the method isDirectory() works vice versa, i.e. it does not scan the path name but accesses the file system for its test.

This enables you to use this main method with the following arguments, where file* are files, directory is a directory and archive.zip is either a ZIP file or does not exist:

src dst Copies to
file1 file2 file2
file directory directory/file
file archive.zip archive.zip/file

I hope this read was useful. For more information, please refer to the Javadoc for the TFile class.