FileChannel Objects in Java, Using View Objects for Different Types

Baldwin shows you how to use the FileChannel class, along with view objects of classes such as DoubleBuffer, to transfer data of all primitive types (other than boolean) between the computer's memory and a physical disk file.

Published:  October 29, 2002
By Richard G. Baldwin

Java Programming Notes # 1790


Preface

New features in SDK Version 1.4.0

The recently released JavaTM 2 SDK, Standard Edition Version 1.4 contains a large number of new features, including the concept of IO channels.  The first lesson in this miniseries, entitled FileChannel Objects in Java, Background Information, introduced you to the concept of channels from a read/write IO viewpoint.  The previous lesson, entitled FileChannel Objects in Java, ByteBuffer Type, showed you the basics of read/write programming using channels.

Showing off the advantages of channels

While the sample program in the previous lesson illustrated the basics of using channels, it didn't do a very good job of showing off the advantages of channels.  The sample program in this and subsequent lessons will do a much better job of showing off the advantages.

Different primitive types

In this lesson, I will show you how to use the FileChannel class, the ByteBuffer class, the DoubleBuffer class, and the ShortBuffer class to transfer data of type double and data of type short between the computer's memory and a physical file.  You will learn how to extend the concept to any primitive data type other than boolean. 

Mixed primitive types

In the next lesson, I will show you how to use the FileChannel class along with the ByteBuffer class to create records consisting of sequences of data values of mixed primitive types, and how to transfer those records between the computer's memory and a physical file.

Memory-mapped IO

Future lessons will teach you how to do memory-mapped IO using channels.

Viewing tip

You may find it useful to open another copy of this lesson in a separate browser window.  That will make it easier for you to scroll back and forth among the different listings and figures while you are reading about them.

Supplementary material

I recommend that you also study the other lessons in my extensive collection of online Java tutorials.  You will find those lessons published at Gamelan.com.  However, as of the date of this writing, Gamelan doesn't maintain a consolidated index of my Java tutorial lessons, and sometimes they are difficult to locate there.  You will find a consolidated index at www.DickBaldwin.com.

What is a FileChannel?

Sun describes an object of the FileChannel class simply as "A channel for reading, writing, mapping, and manipulating a file."

Discussion and Sample Code

I will illustrate the FileChannel class using the sample program named Channel02.  You will find a complete listing of the program in Listing 17 near the end of the lesson.  As is my normal approach, I will discuss this program in fragments.

Writing and reading different primitive types

This program, which was tested using Java SDK version 1.4.0 under Win2000, illustrates the use of FileChannel objects to write and read data of different primitive types from a disk file.

Begin with type double

The program begins by first writing and then reading data of type double using a DoubleBuffer view of a ByteBuffer object.

Applicable to primitive types other than boolean

Then the program illustrates that this approach is applicable to any primitive type (other than boolean) by writing and then reading data of type short using a ShortBuffer view of a ByteBuffer object.

The main method

To keep things simple, the program consists of a main method and several static convenience methods.  The beginning of the main method is shown in Listing 1.

  public static void main(
                        String[] args){
    ByteBuffer bBuf = 
        ByteBuffer.wrap(new byte[56]);

Listing 1

Wrap an array object in a ByteBuffer object

The code in Listing 1 uses the wrap method of the ByteBuffer class to create a ByteBuffer object with a capacity of 56 bytes.  Each byte in the buffer is initialized to a value of zero.  (This is not new.  The methodology for creating ByteBuffer objects was discussed in previous lessons.)

Create a DoubleBuffer view of the ByteBuffer object

The code in Listing 2 is new to this series of tutorial lessons, and is very significant.  This code invokes the asDoubleBuffer method on the ByteBuffer object's reference to create a DoubleBuffer view of the ByteBuffer object.

    DoubleBuffer dBuf = 
                 bBuf.asDoubleBuffer();

Listing 2

DoubleBuffer contents and properties

The content of the DoubleBuffer object starts at the ByteBuffer object's current position, (which is zero in this case).

The DoubleBuffer object's position will be zero.  Its capacity and its limit will be the number of bytes remaining in the ByteBuffer object divided by eight.  Its mark will be undefined.  (The concept of the bytes remaining in a ByteBuffer object was discussed in previous lessons.)

Important, changes will be visible ...

It is very important to note that changes to the ByteBuffer object's content will be visible in the DoubleBuffer object and vice versa.

(Although I can't tell you how the virtual machine manages this data from a physical memory viewpoint, the effect is as if each of the two buffers simply provides a different view of the same data.)

However, even though the two buffers appear to provide different views of the same data, the two buffers' position, limit, and mark values will be independent of one another.

Also reflected in the original array object

Although it isn't demonstrated in this program, changes to the original array object's contents will also be visible in the ByteBuffer object, and in the DoubleBuffer object, and vice versa.  Thus, these two objects simply provide different views of the data in the original array object.  Stated differently, the original array object, the ByteBuffer object, and the DoubleBuffer object all provide different views of the same data.

Units of type double

As you will see later, methods invoked on the DoubleBuffer object operate in units of type double, and not in units of type byte.  This makes it easy, for example, to iterate through the DoubleBuffer object, accessing one double value during each iteration.

Populating the DoubleBuffer object

The code in Listing 3 uses the relative put method of the DoubleBuffer class to populate the DoubleBuffer object with six double values.  (Some of the values, such as 0.6666666666666666, were purposely designed to make full use of the precision of the double type.)

    int cnt = 0;
    for(cnt = 0; cnt < 6; cnt++){
      dBuf.put((cnt+1.0)/3);
    }//end for loop

Listing 3

The relative put method

The relative put method writes the specified double value into the buffer at the current position, and then increments the position by one.

(Several other overloaded versions of the put method are available, including an absolute version that allows you to provide an index that specifies the element into which the double value will be written.)

Prepare for writing to a disk file

At this point, I need to prepare the buffer for writing to a disk file.  In particular, I need to set its limit to the number of values that I want to have written to the file. 

The first statement in Listing 4 sets the limit of the DoubleBuffer object to the number of double values that I have written into the buffer.

    dBuf.limit(cnt);
    bBuf.limit(dBuf.limit()*8);

Listing 4

Will actually write the ByteBuffer to the disk file

Actually, I'm not going to write the DoubleBuffer object to the disk file.  Rather, I will use a FileChannel object to write the backing ByteBuffer object to the disk file.

(FileChannel objects don't deal directly with DoubleBuffer objects, FloatBuffer objects, ShortBuffer objects, etc.  Rather, they deal with the backing ByteBuffer object.)

What I really need to do ...

Therefore, what I really need to do is set the limit on the ByteBuffer object to correspond to the number of bytes consumed by the double values written into the DoubleBuffer object.

After setting the limit on the DoubleBuffer object, the second statement in Listing 4 sets the limit on the backing ByteBuffer object to eight times the limit of the DoubleBuffer object (remember, each double value consists of eight bytes).

Display the DoubleBuffer data

The code in Listing 5 invokes the showDoubleBufferData method to display the contents of the DoubleBuffer object.

    showDoubleBufferData(
                 dBuf,"dBuf-raw data");
                 
Listing 5

The showDoubleBufferData method

The entire showDoubleBufferData method is shown in Listing 6.

  static void showDoubleBufferData(
        DoubleBuffer buf, String name){
    //Displays buffer contents
    
    //Save position
    int pos = buf.position();
    //Set position to zero
    buf.position(0);
    System.out.println(
                   "Data for " + name);
    while(buf.hasRemaining()){
      System.out.println(buf.get());
    }//end while loop
    System.out.println();//new line
    //Restore position and return
    buf.position(pos);
  }//end showDoubleBufferData

Listing 6

Similar to a previous lesson

This method is essentially the same as a similar method that I explained in the previous lesson.  The most significant difference is the fact that the iterative loop (shown in boldface) iterates through the object in eight-byte groups instead of iterating on individual bytes (as was the case in the previous lesson). 

Thus, each invocation of the relative get method retrieves an entire double value (eight bytes) from the DoubleBuffer object, and then increments the value of the position property of the DoubleBuffer object.

The output

The output produced by the code in Listing 6 is shown in Figure 1.

Data for dBuf-raw data
0.3333333333333333
0.6666666666666666
1.0
1.3333333333333333
1.6666666666666667
2.0

Figure 1

Hopefully this is what you expected to see for double data based on division by three.

Return to the main method

Now, I'll return the discussion to the flow of control in the main method.

Getting the size of a disk file

Later on, I'm going to write code to display the number of bytes in a disk file.  I can do that by invoking the size method on a FileChannel object.  I can also do that, (independently of the FileChannel object) by using a File object that represents the file under investigation.

(In this lesson, I chose to take the independent route and use a File object instead of invoking the size method on the FileChannel object.)

Get and save an object of type File

The code in Listing 7 gets a File object that will represent a physical file named junk.txt (when such a file comes into existence).

    String fileName = "junk.txt"; 
    File file = new File(fileName);

Listing 7

(As you may recall, a File object that represents a physical disk file can provide information about the file that it represents, such as its size, its location in the disk file structure, etc.  Note that the use of the File object is not required for the proper operation of this program, other than to make it easy to determine the size of the file.)

Local variables

The code in Listing 8 declares three local reference variables, which will be used later.

    FileOutputStream oStr;
    FileInputStream iStr;
    FileChannel fileChan;

Listing 8

The variables declared in Listing 8 will be used later to hold references to input and output file stream objects, as well as holding a reference to a FileChannel object.

Get FileChannel object for output

In the previous lesson, I showed you that the methodology for getting a FileChannel object (to be used for output only) is:

The code in Listing 9 uses this methodology to get a FileChannel object that can be used to transfer data from a ByteBuffer object to the file named junk.txt.

    //Get FileChannel for output
    try{
      oStr = new FileOutputStream(
                             fileName);
      fileChan = oStr.getChannel();

Listing 9

Write the data to the disk file

The code in Listing 10 invokes the write method of the FileChannel class to write the output data from the ByteBuffer object to the disk file.

      System.out.println(
               "Bytes written = " 
               + fileChan.write(bBuf));

      //Close stream and channel
      oStr.close();
      fileChan.close();

Listing 10

Important, also writes DoubleBuffer data to file

In the process of writing the data from the ByteBuffer object to the disk file, the code in Listing 10 also writes the data from the DoubleBuffer object to the disk file (remember, these are simply different views of the same data).

Recap

The overall process implemented to this point in the program is:

Close the stream and the channel

The code in Listing 10 also closes the FileOutputStream object and the FileChannel object.

Screen output

Note that the invocation of the write method in Listing 10 is in the argument list of a println method.  The write method returns the number of bytes written to the disk file, which is passed to the println method.  Thus, the code in Listing 10 displays the number of bytes written to the disk file as shown in Figure 2.

Bytes written = 48

Figure 2

Six double values at eight bytes each equals ...

Recall that six double values were stored in the DoubleBuffer object.  Each double value requires eight bytes.  Therefore, 48 bytes were written to the disk file named junk.txt.

Get and display the size of the file

Recall the earlier discussion about using a File object that represents the file named junk.txt to get and display the size of the disk file.

      System.out.println(
                     "File length = " +
                        file.length());

Listing 11

The code in Listing 11 invokes the length method on the File object to get and display the size of the file named junk.txt, producing the output shown in Figure 3.

File length = 48

Figure 3

Happily, the size of the file in bytes matches the number of bytes reported earlier as having been written to the file.

(Keep in mind, however, that from our viewpoint, the file really contains six values of type double, each of which requires eight bytes.)

Clear the ByteBuffer object

The code in Listing 12 invokes the method named clearByteBufferData to write a zero value in each element of the ByteBuffer object.

(I discussed this method in detail in the previous lesson, and won't repeat that discussion here.)

      clearByteBufferData(bBuf,"bBuf");

      showDoubleBufferData(
                          dBuf,"dBuf");


Listing 12

Changes made to the ByteBuffer ...

Recall that changes made to the contents of the ByteBuffer object are reflected in the DoubleBuffer object, and vice versa.  Therefore, setting the individual element values to zero in the ByteBuffer object causes the elements in the DoubleBuffer object to also be set to zero.

Display the DoubleBuffer data again

The code in Listing 12 also invokes the showDoubleBufferData method to display the current contents of the DoubleBuffer object.  The code in Listing 12 produces the output shown in Figure 4, which is probably what you expected.

Clear bBuf
Data for dBuf
0.0
0.0
0.0
0.0
0.0
0.0

Figure 4

Why did I clear the ByteBuffer?

The main reason for first clearing and then displaying the contents of the DoubleBuffer object was to show that it no longer contains the six double values written there earlier. 

The contents of the disk file will be read into the DoubleBuffer object, overwriting the current contents of the buffer.  Then the contents will be displayed again, showing that the data was properly read from the disk file back into the buffer.

Get another FileChannel object

The code in Listing 13 uses the same methodology discussed earlier to get a FileChannel object suitable for reading the contents of the physical file named junk.txt into the buffer.

      iStr = new FileInputStream(
                             fileName);
      fileChan = iStr.getChannel();


Listing 13

Read the file data into the buffer

The code in Listing 14 invokes the read method on the FileChannel object to read the contents of the physical file into the ByteBuffer

      System.out.println(
                "Bytes read = " 
                + fileChan.read(bBuf));

      //Close stream and channel
      iStr.close();
      fileChan.close();
      //Display file length

      System.out.println(
                      "File length = " 
                      + file.length());


Listing 14

Then the stream and the channel are both closed.

The number of bytes read

The read method returns the number of bytes read, which is passed to the println method for display.

Then the code in Listing 14 invokes the length method on the File object to get and display the size of the physical file.  These operations produce the output shown in Figure 5.

Bytes read = 48
File length = 48

Figure 5

No surprise here

There should be no surprise that the number of bytes read is reported to be 48 bytes, since that is the size of the file, as shown in Figure 5.

The double data is in the DoubleBuffer object

The read method in Listing 14 reads the contents in the disk file into the ByteBuffer object (and hence into the DoubleBuffer object).

      showDoubleBufferData(
                          dBuf,"dBuf");
                          
Listing 15

Display the double data read from the disk file

The code in Listing 15 displays the contents of the DoubleBuffer object, producing the output shown in Figure 6.

Data for dBuf
0.3333333333333333
0.6666666666666666
1.0
1.3333333333333333
1.6666666666666667
2.0

Figure 6

Again, no surprise

Happily, the current contents of the DoubleBuffer object are the same as the original contents that were written to, and read back from the physical disk file.

What you have learned

Now you know how to use a DoubleBuffer object, in conjunction with a backing ByteBuffer object to manipulate data of type double, including writing the double data to a disk file and reading it back from the disk file.

Classes for other primitive types

The following classes can be used in a similar fashion to manipulate all of the primitive data types except boolean.

Repeat the process for data of type short

For purposes of illustration, the code in Listing 16 essentially repeats the process shown above, using the ShortBuffer class in conjunction with the ByteBuffer class, to manipulate primitive data of type short.

Because of the similarity of this code to the code explained above, I won't discuss this code on a step-by-step basis.  However, the code does contain numerous explanatory comments.

      clearByteBufferData(bBuf,"bBuf");
              
      //Get a DoubleBuffer view of the
      // ByteBuffer object
      ShortBuffer sBuf = 
                  bBuf.asShortBuffer();
      //Populate the ShortBuffer with
      // six short values.  Set its 
      // limit to the number of short
      // values stored there. Force the
      // limit of the ByteBuffer to 
      // track the limit of the 
      // ShortBuffer.
      // Note that it is necessary to 
      // take the number of bytes in a 
      // short into account when 
      // setting the limit on the 
      // ByteBuffer.

      for(cnt = 0; cnt < 6; cnt++){
        sBuf.put(
               (short)(32767/(cnt+1)));
      }//end for loop
      sBuf.limit(cnt);
      bBuf.limit(sBuf.limit()*2);

      //Display the data in the 
      // ShortBuffer
      showShortBufferData(
                 sBuf,"sBuf-raw data");
    
      //Get FileChannel for output
      oStr = new FileOutputStream(
                             fileName);
      fileChan = oStr.getChannel();

      //Write output data from the
      // ByteBuffer to the disk file.
      System.out.println(
               "Bytes written = " 
               + fileChan.write(bBuf));
      //Close stream and channel
      oStr.close();
      fileChan.close();
      //Display file length
      System.out.println(
                      "File length = " 
                      + file.length());

      //Clear the ByteBuffer, which in
      // turn will clear the 
      // ShortBuffer.
      clearByteBufferData(bBuf,"bBuf");

      //Display the ShortBuffer to 
      // confirm that it has been
      // cleared.
      showShortBufferData(
                          sBuf,"sBuf");

      //Get FileChannel for input
      iStr = new FileInputStream(
                             fileName);
      fileChan = iStr.getChannel();

      //Read data from disk file into
      // ByteBuffer.  Then display data
      // in the ShortBuffer.
      System.out.println(
                "Bytes read = " 
                + fileChan.read(bBuf));
      //Close stream and channel
      iStr.close();
      fileChan.close();
      //Display file length
      System.out.println(
                      "File length = " 
                      + file.length());

      //Display data
      showShortBufferData(sBuf,"sBuf");
      

Listing 16

The screen output

The code in Listing 16 produces the output shown in Figure 7.  You will note that the output shown in Figure 7 is very similar to the output in the previous figures, except that Figure 7 reflects data of type short whereas the previous figures reflect data of type double.

Clear bBuf
Data for sBuf-raw data
32767
16383
10922
8191
6553
5461

Bytes written = 12
File length = 12
Clear bBuf
Data for sBuf
0
0
0
0
0
0

Bytes read = 12
File length = 12
Data for sBuf
32767
16383
10922
8191
6553
5461

Figure 7

That's it for now

By now you should understand a quite a lot about the use of the FileChannel class, the Buffer class, and the following view classes:

Run the Program

If you haven't already done so, I encourage you to copy the code from Listing 17 into your text editor, compile it, and execute it.  Experiment with it, making changes, and observing the results of your changes.

Remember, however, that you must be running Java version 1.4.0 or later to compile and execute this program.

Summary

In this lesson, I have shown you how to use the FileChannel class, the ByteBuffer class, the DoubleBuffer class, and the ShortBuffer class to transfer data of type double and data of type short between the computer's memory and a physical file. You have also learned how to extend the concept to any primitive data type other than boolean.

You have learned how to create different primitive views of a ByteBuffer object and how to manipulate the data in the buffer using the primitive views.

You have learned that changes made to the view objects are reflected in the ByteBuffer object and vice versa.  You have also learned that those changes are also reflected in the array object from which the ByteBuffer object was created in the first place.

What's Next?

In the next lesson, I will show you how to use the FileChannel class along with the ByteBuffer class to create records consisting of sequences of data values of mixed primitive types, and how to transfer those records between the computer's memory and a physical file.

In a lesson following that one, I will teach you how to do memory-mapped IO using channels.

Future plans

As time goes on, I plan to publish additional lessons that will help you learn to use other new IO features including:

Complete Program Listing

A complete listing of the program discussed in this lesson is shown in Listing 17 below.
 
/* File Channel02.java
Copyright 2002, R.G.Baldwin
Revised 9/19/02

Illustrates use of FileChannel objects
to write and read data of different 
types from a disk file.

Writes and then reads data using a
DoubleBuffer view of a ByteBuffer.

Then writes and reads data using a
ShortBuffer view of a ByteBuffer.

Tested using JDK 1.4.0 under Win2000

The output is:

Data for dBuf-raw data
0.3333333333333333
0.6666666666666666
1.0
1.3333333333333333
1.6666666666666667
2.0

Bytes written = 48
File length = 48
Clear bBuf
Data for dBuf
0.0
0.0
0.0
0.0
0.0
0.0

Bytes read = 48
File length = 48
Data for dBuf
0.3333333333333333
0.6666666666666666
1.0
1.3333333333333333
1.6666666666666667
2.0

Clear bBuf
Data for sBuf-raw data
32767
16383
10922
8191
6553
5461

Bytes written = 12
File length = 12
Clear bBuf
Data for sBuf
0
0
0
0
0
0

Bytes read = 12
File length = 12
Data for sBuf
32767
16383
10922
8191
6553
5461

**************************************/

import java.io.*;
import java.nio.channels.*;
import java.nio.*;

class Channel02{
  public static void main(
                        String[] args){
 
    //Create a ByteBuffer with a 
    // capacity of 56 bytes, and all
    // elements initialized to zero.
    ByteBuffer bBuf = 
        ByteBuffer.wrap(new byte[56]);
        
    //Get a DoubleBuffer view of the
    // ByteBuffer object
    DoubleBuffer dBuf = 
                 bBuf.asDoubleBuffer();
                                  
    //Populate the DoubleBuffer with
    // six double values.  Set its 
    // limit to the number of double
    // values stored there.  Force the
    // limit of the ByteBuffer to track
    // the limit of the DoubleBuffer.
    // Note that it is necessary to 
    // take the number of bytes in a 
    // double into account when setting
    // the limit on the ByteBuffer.
    int cnt = 0;
    for(cnt = 0; cnt < 6; cnt++){
      dBuf.put((cnt+1.0)/3);
    }//end for loop
    dBuf.limit(cnt);
    bBuf.limit(dBuf.limit()*8);

    //Display the data in the 
    // DoubleBuffer
    showDoubleBufferData(
                 dBuf,"dBuf-raw data");
                 
    //Get a File object to represent
    // a physical file.  Will use it
    // later to get the file length.
    String fileName = "junk.txt"; 
    File file = new File(fileName);
    
    //Declare variables for use later
    FileOutputStream oStr;
    FileInputStream iStr;
    FileChannel fileChan;

    //Get FileChannel for output
    try{
      oStr = new FileOutputStream(
                             fileName);
      fileChan = oStr.getChannel();

      //Write output data from the
      // ByteBuffer to the disk file.
      System.out.println(
               "Bytes written = " 
               + fileChan.write(bBuf));
      //Close stream and channel
      oStr.close();
      fileChan.close();
      //Display file length
      System.out.println(
                     "File length = " +
                        file.length());
      
      //Clear the ByteBuffer, which in
      // turn will clear the 
      // DoubleBuffer.
      clearByteBufferData(bBuf,"bBuf");

      //Display the DoubleBuffer to 
      // confirm that it has been
      // cleared.
      showDoubleBufferData(
                          dBuf,"dBuf");

      //Get FileChannel for input
      iStr = new FileInputStream(
                             fileName);
      fileChan = iStr.getChannel();

      //Read data from disk file into
      // ByteBuffer.  Then display data
      // in the DoubleBuffer.
      System.out.println(
                "Bytes read = " 
                + fileChan.read(bBuf));
      //Close stream and channel
      iStr.close();
      fileChan.close();
      //Display file length
      System.out.println(
                      "File length = " 
                      + file.length());

      //Display data
      showDoubleBufferData(
                          dBuf,"dBuf");
                          
      //Now repeat the process using 
      // the same ByteBuffer and the
      // same disk file, but using a
      // ShortBuffer view and 
      // populating the buffer with
      // primitive short data.
        
      clearByteBufferData(bBuf,"bBuf");
              
      //Get a DoubleBuffer view of the
      // ByteBuffer object
      ShortBuffer sBuf = 
                  bBuf.asShortBuffer();
      //Populate the ShortBuffer with
      // six short values.  Set its 
      // limit to the number of short
      // values stored there. Force the
      // limit of the ByteBuffer to 
      // track the limit of the 
      // ShortBuffer.
      // Note that it is necessary to 
      // take the number of bytes in a 
      // short into account when 
      // setting the limit on the 
      // ByteBuffer.

      for(cnt = 0; cnt < 6; cnt++){
        sBuf.put(
               (short)(32767/(cnt+1)));
      }//end for loop
      sBuf.limit(cnt);
      bBuf.limit(sBuf.limit()*2);

      //Display the data in the 
      // ShortBuffer
      showShortBufferData(
                 sBuf,"sBuf-raw data");
    
      //Get FileChannel for output
      oStr = new FileOutputStream(
                             fileName);
      fileChan = oStr.getChannel();

      //Write output data from the
      // ByteBuffer to the disk file.
      System.out.println(
               "Bytes written = " 
               + fileChan.write(bBuf));
      //Close stream and channel
      oStr.close();
      fileChan.close();
      //Display file length
      System.out.println(
                      "File length = " 
                      + file.length());

      //Clear the ByteBuffer, which in
      // turn will clear the 
      // ShortBuffer.
      clearByteBufferData(bBuf,"bBuf");

      //Display the ShortBuffer to 
      // confirm that it has been
      // cleared.
      showShortBufferData(
                          sBuf,"sBuf");

      //Get FileChannel for input
      iStr = new FileInputStream(
                             fileName);
      fileChan = iStr.getChannel();

      //Read data from disk file into
      // ByteBuffer.  Then display data
      // in the ShortBuffer.
      System.out.println(
                "Bytes read = " 
                + fileChan.read(bBuf));
      //Close stream and channel
      iStr.close();
      fileChan.close();
      //Display file length
      System.out.println(
                      "File length = " 
                      + file.length());

      //Display data
      showShortBufferData(sBuf,"sBuf");
      
    }catch(Exception e){
      System.out.println(e);}
  }// end main

  //---------------------------------//
  static void showDoubleBufferData(
        DoubleBuffer buf, String name){
    //Displays buffer contents
    
    //Save position
    int pos = buf.position();
    //Set position to zero
    buf.position(0);
    System.out.println(
                   "Data for " + name);
    while(buf.hasRemaining()){
      System.out.println(buf.get());
    }//end while loop
    System.out.println();//new line
    //Restore position and return
    buf.position(pos);
  }//end showDoubleBufferData
  //---------------------------------//

  static void showShortBufferData(
         ShortBuffer buf, String name){
    //Displays buffer contents
    
    //Save position
    int pos = buf.position();
    //Set position to zero
    buf.position(0);
    System.out.println(
                   "Data for " + name);
    while(buf.hasRemaining()){
      System.out.println(buf.get());
    }//end while loop
    System.out.println();//new line
    //Restore position and return
    buf.position(pos);
  }//end showShortBufferData
  //---------------------------------//
  
  static void clearByteBufferData(
          ByteBuffer buf, String name){
    //Stores 0 in each element of a
    // byte buffer.
    
    //Set position to zero
    buf.position(0);
    System.out.println(
                      "Clear " + name);
    while(buf.hasRemaining()){
      buf.put((byte)0);
    }//end while loop
    //Set position to zero and return
    buf.position(0);
  }//end clearByteBufferData
  //---------------------------------//
  
}//end class Channel02 definition

Listing 17

Copyright 2002, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects, and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which has gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com

-end-