CHAPTER 8 ■ WRITING AND READING FILES
Before we proceed with reviewing the file, let's examine the reverseByteArray method. It does
what's called in-place reversing, because we modify the original object without using any additional
memory. Because we use the same memory area that the object already modifies, it's said to be “in-
place.” We can do that because Java passes memory addresses rather than values for objects (such as an
array). We can’t do it for a primitive, because Java passes copies of values for primitives. Many
developers prefer in-place operations because they consume less memory and generally perform more
quickly than code that makes copies of things and then modifies the copies.
This particular reversing algorithm works from both ends of the input at once, by the way. Although
you might think we have to worry about whether we have an even number or odd number of bytes, we
don't actually need to concern ourselves with that detail. If we start with an even number of bytes, we
walk down the array to the middle and swap the center two bytes. With an odd number of bytes, the byte
at the center simply never moves. Also, shifting to the right by one is a smidgeon faster than dividing by
two. Combined with working from both ends at once and doing the reversal in place (that is, by not
creating an additional array to hold intermediate results), this reversing algorithm is about as fast as a
reversing algorithm can be, making it a handy trick to remember.
Alternately, we can reverse the contents of the file by using Java's StringBuffer class. To do so, we
have to convert the content variable to a String object, create an instance of the StringBuffer class, call
the reverse method on the StringBuffer object, and convert the result of StringBuffer.reverse back into a
byte array. Listing 8-15 shows that alternate way to reverse the contents of a byte array.
Listing 8-15. Another way to reverse a byte array
String contentString = content.toString();
StringBuffer sb = new StringBuffer(contentString);
sb.reverse();
content = sb.toString().getBytes();
I showed you another way to reverse the contents of a byte to demonstrate that there's almost
always another way to do things and to illustrate an issue you should know about: Conversion is
expensive. The code in Listing 8-15 does a number of conversions (both of the toString methods and
the getBytes method are conversions). Conversions consume both time and memory, though, so you
can optimize your code by using an algorithm that doesn't demand conversions. Conversely, the
reverseByteArray method does all of its work with bytes and never tries to convert to another type, so it
ties up fewer resources (memory) and runs more quickly. Try to remember to not convert between types
unless you must.
Now examine the contents of hamlet.txt. You find it's completely reversed, as shown in Listing
8-16.
Listing 8-16. Hamlet in reverse
efil gnol os fo ytimalac sekam tahT
tcepser eht s'ereht :esuap su evig tsuM
,lioc latrom siht ffo delffuhs evah ew nehW
emoc yam smaerd tahw htaed fo peels taht ni roF
;bur eht s'ereht ,ya :maerd ot ecnahcrep :peels oT
So now you see how to open a file, read its content, and replace (and reverse) that content. We can
also modify the file's content rather than replace it. One simple operation is to append our new content
to the existing content. To do so, we need to specify that we want to append to the file when we open it,
by using a different File constructor. To get it to print nicely, we also put a newline character ('\n')