23.07.2013 Views

Java IO.pdf - Nguyen Dang Binh

Java IO.pdf - Nguyen Dang Binh

Java IO.pdf - Nguyen Dang Binh

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

}<br />

* possible that this number is temporarily less than the actual<br />

* number of bytes written.)<br />

* @return the value of the written field.<br />

* @see java.io.LittleEndianOutputStream#written<br />

*/<br />

public int size() {<br />

return this.written;<br />

}<br />

<strong>Java</strong> I/O<br />

Notice how all writing is done by passing byte values to the underlying output stream out (set<br />

in the constructor and inherited from the superclass, FilterOutputStream). The primary<br />

purpose of these methods is to convert the <strong>Java</strong> data type to bytes and then write them in a<br />

little-endian order. In general, the conversions are accomplished by shifting the bits of interest<br />

into the low-order eight bits, then masking off the bits of interest. For example, consider the<br />

writeInt() method:<br />

public void writeInt(int i) throws <strong>IO</strong>Exception {<br />

}<br />

out.write(i & 0xFF);<br />

out.write((i >>> 8) & 0xFF);<br />

out.write((i >>> 16) & 0xFF);<br />

out.write((i >>> 24) & 0xFF);<br />

written += 4;<br />

A <strong>Java</strong> int is composed of four bytes in big-endian order. Thus, the low-order byte is in the<br />

last eight bits. This byte needs to be written first in a little-endian scheme. The mask 0xFF has<br />

one bit in the low-order eight bits and zero bits everywhere else. By bitwise ANDing 0xFF<br />

with i, we select the low-order eight bits of i. The second-lowest-order byte—that is, bits 16<br />

to 23—is selected by first shifting the bits right without sign extension into the low-order bits.<br />

That's the purpose of (i >>> 8). Then this byte can be retrieved with the same 0xFF mask used<br />

before. The same is done for the second-to-lowest-order byte and the highest-order byte.<br />

Here, however, it's necessary to shift by 16 and 24 bits, respectively.<br />

floats and doubles are converted to ints and longs using Float.floatToIntBits() and<br />

Double.doubleTolongBits(), then invoking writeInt() or writeLong() to write those<br />

bits in little-endian order.<br />

Each method increments the protected field written by the number of bytes actually written.<br />

This tracks the total number of bytes written onto the output stream at any one time. This<br />

incurs a surprising amount of overhead. If this class did not track the number of bytes written,<br />

it could be several methods shorter. Furthermore, there is a potential synchronization problem,<br />

which happens to be shared by DataOutputStream. It is possible for one thread to interrupt a<br />

method like writeInt() after it has written some data but before the written field has been<br />

updated. It would be simple to fix this problem by declaring all methods that update written<br />

as synchronized. However, that would be a huge performance hit, so I've elected to follow<br />

the example of DataOutputStream and not synchronize these methods.<br />

Example 7.9 is the corresponding LittleEndianInputStream class, based on the<br />

DataInputStream class.<br />

117

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!