«« Super Size Me | Main Page | MT-Blacklist Kicks Ass »»
blog header image
Java New I/O for Abstractions and ... Perf? Yes.

If you were used to dealing with Java I/O the old way, the New I/O APIs in Java 1.4 are really handy.

The first is the notion of channels. I use a FileChannel to copy the bytes of a source file to a destination file. The API is dead simple to use too:

RandomAccessFile s = new RandomAccessFile(sourceFile, "r");
RandomAccessFile d = new RandomAccessFile(destFile, "rw");

FileChannel source = s.getChannel();
FileChannel destination = d.getChannel();

source.transferTo(start, count, destination);

You don't have to read a chunk of bytes from the source file and write them to the destination file in a while loop -- it's all done for you. Roy has been testing this code for me and he says it's really fast too. Sweet.

Another nice class in nio is ByteBuffer, which I used in jid3rL. I also used his brother CharBuffer to read encoded buffers of chars[1]. A ByteBuffer is just a wrapper around a byte[], and a CharBuffer is a wrapper around a char[]. You can use the Charset class to decode a ByteBuffer to a CharBuffer or encode a CharBuffer to a ByteBuffer in a specific character encoding.

Buffers also keep track of where you are in the wrapped array. You can make your way through the buffer, pass it around to other methods and the current position and array length are passed as well. This makes ByteBuffer really handy for parsing bytes, and CharBuffer for parsing chars.

In particular I simplified my frame parsing code a lot by using a ByteBuffer and a method I made to pop the next null-terminated string off the front of it. It cleans up the frame parsing code nicely: I'm not looping through bytes looking for null in my frame parsing code any more, it's all abstracted. The great thing about this abstraction of course is that (encoded) String parsing is centralized now, leading to less errors in frame parsing code itself.

This is the intermediate step towards specifying frame fields with constants, like I mentioned before. These constants will specify for each frame field the type expected, it's maximum and minimum length, etc. Then you put it in a general frame field parser that understands how to parse all of the field types to objects from a byte[]. You get an array of parsed Objects back.

If all of the field values are in an Object array in the Frame subclasses, then the Frame superclass can handle general implementations of equals(), hashCode() and toString() and other methods. Not only will this save me from implementing all of these methods in the subclasses (there will be about forty), but it will also save me from testing them too.

Thinking about testing is often encouragement to get rid of code duplication, because if you have code duplication you'll end up with test duplication too. Who wants to write more tests then they have to?

[1] id3v2 supports Unicode UTF-8 and UTF-16.

Posted at September 01, 2004 at 04:57 PM EST
Last updated September 01, 2004 at 04:57 PM EST

I think that you wanted to call your destination "d" and not "s"


» Posted by: Jim at September 2, 2004 09:15 AM

Good eye, Jimbo. Don't worry, that code wasn't pasted from my real code. :D

» Posted by: Ryan at September 2, 2004 09:54 AM

Search scope: Web ryanlowe.ca