SDK 1.4 contains a number of features for improved input/output processing, collectively called the "new I/O," in the java.nio package. (Of course, the "new" moniker is somewhat regrettable because, a few years down the road, the package won't be new any longer.) The package includes support for the following features:

We discuss only the first three features here. Non-blocking I/O requires the use of threads, which are covered in Volume 2.

Memory-Mapped Files

Most operating systems can take advantage of the virtual memory implementation to "map" a file, or a region of a file, into memory. Then the file can be accessed as if it was an in-memory array, which is much faster than the traditional file operations. At the end of this section, you will find two short programs that compute the CRC32 checksum of a file. One version reads the file data with the read method, the other uses a memory-mapped file. The second version is dramatically faster. On one machine, we got the following timing data when computing the checksum of the 22MB file rt.jar in the jre/lib directory of the SDK.

Of course, the exact values will differ greatly from one machine to another, but it is obvious that the performance gain can be substantial. The java.nio package makes memory mapping quite simple. Here is what you need to do. First, get a channel from the file. A channel is a new abstraction for disk files that lets you access operating system features such as memory mapping, file locking, and fast data transfers between files. You get a channel by calling the getChannel method that has been added to the FileInputStream, FileOutputStream, and RandomAccessFile class.

FileInputStream in = new FileInputStream(. . .);
FileChannel channel = in.getChannel();

Then you get a MappedByteBuffer from the channel by calling the map method of the FileChannel class. You specify the area of the file that you want to map and a mapping mode. Three modes are supported:

Once you have the buffer, you can read and write data, using the methods of the ByteBuffer class and the Buffer superclass. Buffers support both relative and absolute data access. A buffer has a position that is advanced by get and put operations. For example, you can traverse all bytes in the buffer as

while (buffer.hasRemaining())
{
 byte b = buffer.get();
 . . .
}

Alternatively, you can use absolute addressing:

for (int i = 0; i < buffer.limit(); i++)
{
 byte b = buffer.get(i);
 . . .
}

You can also read and write arrays of bytes with the methods

get(byte[] bytes)
get(byte[], int offset, int length)

Finally, there are methods

getInt getLong getShort getChar getFloat getDouble

to read primitive type values that are stored as binary values in the file. For example, the integer 1234 would be stored as a sequence of four bytes

00 00 04 D2

(in hexadecimal), since 1234 = 4 x 256 + 13 x 16 + 2. Actually, there are two ways of storing 1234 as a binary value, depending on the byte ordering. The byte ordering given above is called "big-endian" since the more significant bytes come first. Another ordering, called "little-endian," starts with the least significant byte:

D2 04 00 00

By default, Java uses big-endian ordering, probably because that is the ordering used in Sun SPARCS processors. However, the Intel processors use little-endian byte ordering. Therefore, file formats with a PC pedigree often store binary numbers in little-endian order. If you need to process such a file, simply call

buffer.order(ByteOrder.LITTLE_ENDIAN);

To find out the current byte order of a buffer, call

ByteOrder b = buffer.order()

Java graphics caution_icon

This pair of methods does not use the set/get naming convention.To write numbers to a buffer, use one of the methods

putInt putLong putShort putChar putFloat putDouble

and are two programs that compute the 32-bit cyclic redundancy checksum (CRC32) of a file. That quantity is a checksum that is often used to determine whether a file has been corrupted. Corruption of a file makes it very likely that the checksum has changed. The java.util.zip package contains a class CRC32 that computes the checksum of a sequence of bytes, using the following loop:

CRC32 crc = new CRC32();
while (more bytes)
 crc.update(next byte)
long checksum = crc.getValue();

Java graphics notes_icon

For a nice explanation of the CRC algorithm, see .The details of the CRC computation are not important. We just use it as an example of a useful file operation. The first program uses traditional file input, and the second uses memory mapping. As we already said, the second one is much faster. Try it out. Run both programs with the same file, as

java CRC filename

and

java NIOCRC filename

Example CRC.java

 1. import java.io.*;
 2. import java.util.zip.*;
 3.
 4. /**
 5. This program computes the CRC checksum of a file, using
 6. an input stream.
 7. Usage: java CRC filename
 8. */
 9. public class CRC
10. {
11. public static void main(String[] args) throws IOException
12. {
13. InputStream in = new FileInputStream(args[0]);
14. CRC32 crc = new CRC32();
15. int c;
16. long start = System.currentTimeMillis();
17. while((c = in.read()) != -1)
18. crc.update(c);
19. long end = System.currentTimeMillis();
20. System.out.println(Long.toHexString(crc.getValue()));
21. System.out.println((end - start) + " milliseconds");
22. }
23.
24. }

Example NIOCRC.java

 1. import java.io.*;
 2. import java.nio.*;
 3. import java.nio.channels.*;
 4. import java.util.zip.*;
 5.
 6. /**
 7. This program computes the CRC checksum of a file, using
 8. a memory-mapped file.
 9. Usage: java CRC filename
10. */
11. public class NIOCRC
12. {
13. public static void main(String[] args) throws Exception
14. {
15. FileInputStream in = new FileInputStream(args[0]);
16. FileChannel channel = in.getChannel();
17.
18. CRC32 crc = new CRC32();
19. long start = System.currentTimeMillis();
20.
21. MappedByteBuffer buffer = channel.map(
22. FileChannel.MapMode.READ_ONLY, 0, (int)channel.size());
23. while (buffer.hasRemaining())
24. crc.update(buffer.get());
25.
26. long end = System.currentTimeMillis();
27. System.out.println(Long.toHexString(crc.getValue()));
28. System.out.println((end - start) + " milliseconds");
29. }
30. }

java.io.FileInputStream 1.0

Java graphics api_icon

java.io.FileOutputStream 1.0

Java graphics api_icon

java.io.RandomAccessFile 1.0

Java graphics api_icon

java.nio.channels.FileChannel 1.4

Java graphics api_icon