Chapter: Java The Complete Reference - The Java Library - Input/Output: Exploring java.io

Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail

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.

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.


Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail


Copyright © 2018-2020 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.