Pre-JDK 7 Channel-Based Examples
Before
concluding this chapter, one more aspect of NIO needs to be covered. The
preceding sections have used several of the new features added to NIO by JDK 7.
However, you may encounter pre-JDK 7 code that will need to be maintained or
possibly converted to use the new features. For this reason, the following
sections show how to read and write files using the pre-JDK 7 NIO system. They
do so by reworking some of the examples shown earlier so that they use the
original NIO features, rather than those supported by NIO.2. This means that
the examples in this section will work with versions of Java prior to JDK 7.
The key
difference between pre-JDK 7 NIO code and newer NIO code is the Path interface, which was added by JDK
7. Thus, pre-JDK 7 code does not use Path
to describe a file or open a channel to it. Also, pre-JDK 7 code does not use try-with-resource statements since
automatic resource management was also added by JDK 7.
Read a File, Pre-JDK 7
This
section reworks the two channel-based file input examples shown earlier so they
use only pre-JDK 7 features. The first example reads a file by manually
allocating a buffer and then performing an explicit read operation. The second
example uses a mapped file, which automates the process.
When
using a pre-JDK 7 version of Java to read a file using a channel and a manually
allocated buffer, you first open the file for input using FileInputStream, using the same mechanism explained in Chapter 20.
Next, obtain a channel to this file by calling getChannel( ) on the FileInputStream
object. It has this general form:
FileChannel
getChannel( )
It
returns a FileChannel object, which
encapsulates the channel for file operations. Then, call allocate( ) to allocate a buffer. Because file channels operate on
byte buffers, you will use the allocate(
) method defined by ByteBuffer,
which works as previously described.
The
following program shows how to read and display a file called test.txt through a channel using
explicit input operations for versions of Java prior to JDK 7:
// Use Channels to read a
file. Pre-JDK 7 version.
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class
ExplicitChannelRead {
public static void
main(String args[]) { FileInputStream fIn = null; FileChannel fChan = null;
ByteBuffer mBuf; int count;
try {
// First, open a file for
input.
fIn = new
FileInputStream("test.txt");
//Next, obtain a channel to that file.
fChan = fIn.getChannel();
Allocate a buffer.
mBuf =
ByteBuffer.allocate(128);
do {
// Read a buffer.
count = fChan.read(mBuf);
// Stop when end of file is
reached.
if(count != -1) {
//Rewind the buffer so that it can be read.
mBuf.rewind();
//Read bytes from the buffer and show them on
the screen.
for(int i=0; i < count;
i++)
System.out.print((char)mBuf.get());
}
} while(count != -1);
System.out.println();
} catch (IOException e) {
System.out.println("I/O Error " + e);
} finally { try {
if(fChan != null)
fChan.close(); // close channel
} catch(IOException e) {
System.out.println("Error
Closing Channel.");
}
try {
if(fIn != null) fIn.close();
// close file
} catch(IOException e) {
System.out.println("Error Closing File.");
}
}
}
}
In this
program, notice that the file is opened by using the FileInputStream constructor, and a reference to that object is
assigned to fIn. Next, a channel
connected to the file is obtained by calling getChannel( ) on fIn.
After this point, the program works like the NIO.2 version shown previously. To
synopsize: The program then calls the allocate(
) method of ByteBuffer to
allocate a buffer that will hold the contents of the file when it is read. A
byte buffer is used because FileChannel operates on bytes. A
reference to this buffer is stored in mBuf.
The contents of the file are then read, one buffer at a time, into mBuf through a call to read( ). The number of bytes read is stored in count. Next, the buffer is rewound through a call to rewind( ). This call is necessary
because the current position is at the end of the buffer after the call to read( ), and it must be reset to the
start of the buffer in order for the bytes in mBuf to be read by calling get(
). When the end of the file has been reached, the value returned by read( ) will be –1. When this occurs,
the program ends, explicitly closing the channel and the file.
Another
way to read a file is to map it to a buffer. As explained earlier, a principal
advantage to this approach is that the buffer automatically contains the
contents of the file. No explicit read operation is necessary. To map and read
the contents of a file using pre-JDK 7 NIO, first open the file using FileInputStream. Next, obtain a channel
to that file by calling getChannel( )
on the file object. Then, map the channel to a buffer by calling map( ) on the FileChannel object. The
map( ) method works as described earlier.
The
following program reworks the preceding example so that it uses only pre-JDK 7
features to create a mapped file:
// Use a mapped file to read
a file. Pre-JDK 7 version.
import java.io.*; import
java.nio.*;
import java.nio.channels.*;
public class
MappedChannelRead {
public static void
main(String args[]) { FileInputStream fIn = null; FileChannel fChan = null;
long fSize; MappedByteBuffer
mBuf;
try {
// First, open a file for
input.
fIn = new
FileInputStream("test.txt");
//Next, obtain a channel to that file.
fChan = fIn.getChannel();
//Get the size of the file.
fSize = fChan.size();
// Now, map the file into a
buffer.
mBuf =
fChan.map(FileChannel.MapMode.READ_ONLY, 0, fSize);
// Read and display bytes
from buffer.
for(int i=0; i < fSize;
i++)
System.out.print((char)mBuf.get());
} catch (IOException e) {
System.out.println("I/O Error " + e);
} finally { try {
if(fChan != null)
fChan.close(); // close channel
} catch(IOException e) {
System.out.println("Error
Closing Channel.");
}
try {
if(fIn != null) fIn.close();
// close file
} catch(IOException e) {
System.out.println("Error Closing File.");
}
}
}
}
In the
program, the file is opened by using the FileInputStream
constructor, and a reference to that object is assigned to fIn. A channel connected to the file is obtained by calling getChannel( ) on fIn. Next, the size of the file is obtained. Then, the entire file
is mapped into memory by calling map( ),
and a reference to the buffer is stored in mBuf.
The bytes in mBuf are read by
calling get( ).
Write to a File, Pre-JDK 7
This
section reworks the two channel-based file output examples shown earlier so
that they use only pre-JDK 7 features. The first example writes to a file by
manually allocating a buffer and then performing an explicit output operation.
The second example uses a mapped file, which automates the process. In both
cases, neither Path nor try-with-resources is used. This is
because neither were part of Java until JDK 7.
When
using a pre-JDK 7 version of Java to write a file using a channel and a
manually allocated buffer, first open the file for output. This is done by
creating a FileOutputStream, as
described in Chapter 20. Next, obtain a channel to the file by calling getChannel( ) and then allocate a byte
buffer by calling allocate( ), as
described in the previous section. Next, put the data you want to write into
that buffer, and then call write( )
on the channel. The following program demonstrates this procedure. It writes
the alphabet to a file called test.txt.
// Write to a file using NIO.
Pre-JDK 7 Version.
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class
ExplicitChannelWrite {
public static void
main(String args[]) { FileOutputStream fOut = null; FileChannel fChan = null;
ByteBuffer mBuf;
try {
// First, open the output
file.
fOut = new FileOutputStream("test.txt");
Next, get a channel to the output file.
fChan = fOut.getChannel();
Create a buffer.
mBuf =
ByteBuffer.allocate(26);
//Write some bytes to the buffer.
for(int i=0; i<26; i++)
mBuf.put((byte)('A' + i));
//Rewind the buffer so that it
can be written.
mBuf.rewind();
// Write the buffer to the output file.
fChan.write(mBuf);
} catch (IOException e) {
System.out.println("I/O Error " + e);
} finally { try {
if(fChan != null)
fChan.close(); // close channel
} catch(IOException e) {
System.out.println("Error
Closing Channel.");
}
try {
if(fOut != null)
fOut.close(); // close file
} catch(IOException e) {
System.out.println("Error Closing File.");
}
}
}
}
The call
to rewind( ) on mBuf is necessary in order to reset the current position to zero
after data has been written to mBuf.
Remember, each call to put( )
advances the current position. Therefore, it is necessary for the current
position to be reset to the start of the buffer before calling write( ). If this is not done, write( ) will think that there is no
data in the buffer.
When
using a pre-JDK 7 version of Java to write to a file using a mapped file,
follow these steps. First, open the file for read/write operations by creating
a RandomAccessFile object. This is
necessary to enable the file to be both read from and written to. Next, map
that file to a buffer by calling map( )
on that object. Then, write to the buffer. Because the buffer is mapped to the
file, any changes to that buffer are automatically reflected in the file. Thus,
no explicit write operations to the channel are necessary.
Here is
the preceding program reworked so that a mapped file is used:
// Write to a mapped file.
Pre JDK 7 version.
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class
MappedChannelWrite {
public static void
main(String args[]) { RandomAccessFile fOut = null; FileChannel fChan = null;
ByteBuffer mBuf;
try {
fOut = new
RandomAccessFile("test.txt", "rw");
//Next, obtain a channel to that file.
fChan = fOut.getChannel();
//Then, map the file into a buffer.
mBuf =
fChan.map(FileChannel.MapMode.READ_WRITE, 0, 26);
// Write some bytes to the
buffer.
for(int i=0; i<26; i++)
mBuf.put((byte)('A' + i));
} catch (IOException e) {
System.out.println("I/O Error " + e);
} finally { try {
if(fChan != null)
fChan.close(); // close channel
} catch(IOException e) {
System.out.println("Error
Closing Channel.");
}
try {
if(fOut != null)
fOut.close(); // close file
} catch(IOException e) {
System.out.println("Error Closing File.");
}
}
}
}
As you
can see, there are no explicit write operations to the channel itself. Because mBuf is mapped to the file, changes to mBuf are automatically reflected in the
underlying file.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.