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.