November 28, 2014
Hot Topics:

FileChannel Objects in Java, Records with Mixed Types

  • November 14, 2002
  • By Richard G. Baldwin
  • Send Email »
  • More Articles »

All primitive types other than boolean ...

Thus, the ByteBuffer class makes it easy for you to store data of all primitive types (other than boolean) in a ByteBuffer object. 

If you use the relative version of the put... method, the value of the position property will be properly incremented for the type of data being stored during each put operation.

(If you mix data types in the buffer, you must be careful to make certain that you retrieve them in the same order that you store them.  Otherwise, you will get the bytes scrambled among the different primitive values.)

The putRecord method stores three primitive types

Each time the method named putRecord in Listing 3 is invoked, it stores three primitive values (in the order char, byte, and float) into the ByteBuffer object.

How many bytes are required for a record?

The char type requires two bytes.  The byte type requires one byte, and the float type requires four bytes.  Thus, each record, consisting of the three values, requires seven bytes for storage. 

Therefore, each time the putRecord method in Listing 3 is invoked, the value of the location property of the ByteBuffer object is advanced by seven bytes. 

Assuming that the location property has a value of zero at the beginning, each group of seven bytes contains a record as defined in this program.

Of course, you could define your records to contain any combination of primitive types (other than boolean) in any order, so your records may have a different length.

Now back to the flow in main ...

Now that you understand the behavior of the putRecord method, let's return to the flow of control in the main method.

Create and store another record

The code in Listing 4 simply creates another record and adds it to the ByteBuffer object.

      cData = 'B';
      bData = 28;
      fData = (float)2.0/3;
      putRecord(
               bBuf,cData,bData,fData);

Listing 4

When the putRecord method returns from this second invocation, two records, consisting of fourteen data bytes will have been stored in the ByteBuffer object.

Prepare properties for a disk write operation

In preparation for writing these two records to a disk file, the code in Listing 5 sets the limit property of the ByteBuffer object to the current value of the position property, and then sets the value of the position property to zero.

      bBuf.limit(bBuf.position());
      bBuf.position(0);

Listing 5

This has the effect of causing the data written to the disk file to start at the beginning of the ByteBuffer object and to be limited to the number of bytes stored in the ByteBuffer object.

(This is as opposed to writing the entire ByteBuffer object to the disk file based on its capacity.)

Display the records

The code in Listing 6 invokes the showRecords method to display the records stored in the ByteBuffer object.

      showRecords(bBuf);

Listing 6

The showRecords method

At this point, I will depart from the main method and explain the behavior of the showRecords method, as shown in Listing 7.

  static void showRecords(
                      ByteBuffer bBuf){
    
    //Save position
    int pos = bBuf.position();
    //Set position to zero
    bBuf.position(0);
    System.out.println(
                   "Records");

    while(bBuf.hasRemaining()){
      System.out.println(
                bBuf.getChar() + " " + 
                bBuf.get() + " " + 
                bBuf.getFloat());
    }//end while loop

    System.out.println();//new line
    //Restore position and return
    bBuf.position(pos);
  }//end showRecords

Listing 7

If you understood the explanation of the relative put methods earlier, the code in Listing 7 should be easy to understand.

The iterative loop

The code in Listing 7 that is new to this lesson is the boldface iterative loop in the center of the listing.  The code before and after the iterative loop is the same as code that I have explained in previous lessons.

The get methods of the ByteBuffer class

As is the case with the put methods, the ByteBuffer class provides the following methods for retrieving primitive data, by type, from a ByteBuffer object:

  • get
  • getChar
  • getDouble
  • getFloat
  • getInt
  • getLong
  • getShort

Relative and absolute versions of the get methods

As with the put methods, there is a relative version and an absolute version of each of these methods.  For example, the relative version of the getChar() method can be described as follows:

Relative get method for reading a char value.  Reads the next two bytes at this buffer's current position, composing them into a char value according to the current byte order, and then increments the position by two.  Returns the char value at the buffer's current position.

Retrieving primitive data from a ByteBuffer object

Thus, the ByteBuffer class makes it easy for you to retrieve data of all primitive types (other than boolean) from a ByteBuffer object. 

If you use the relative version of the appropriate get... method, the value of the position property will be properly incremented for the type of data being retrieved during each get operation.

(If you mix data types in the buffer, you must make certain that you retrieve the primitive values in the same order that you store them.  Otherwise, you will get the bytes scrambled among the different primitive values.)

Output data

Now that you understand the behavior of the showRecords method, I will return to the flow of control in the main method.  First however, I need to tell you that the output produced by the invocation of the showRecords method at this point in the program is shown in Figure 1.

Records
A 14 0.33333334
B 28 0.6666667

Figure 1

Figure 1 displays one record on each line of output, where each record consists of a char, a byte, and a float (Hopefully, this is what you expected each record to look like.)

Get a FileChannel object for output

Returning to the flow of control in the main method, Listing 8 uses code similar to code that I have discussed in previous lessons to get a FileChannel object for output to a disk file named junk.txt.

      oStr = new FileOutputStream(
                           "junk.txt");
      fileChan = oStr.getChannel();

Listing 8

Write the file and display the file size

Similarly, Listing 9 uses code that I have explained in previous lessons to:

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

Listing 9

(In the programs in previous lessons, I used a File object to get an independent report on the size of the file.  In this program, I used the size() method of the FileChannel class to get the size of the file.)

The file size output

The code in Listing 9 produces the output shown in Figure 2.

Bytes written = 14
File length = 14

Figure 2

Figure 2 shows the number of bytes that we would expect to be written based on our previous analysis of the number of bytes required to store each of the two records.

Clear the buffer and display its contents

The code in Listing 10 sets the value of each byte in the ByteBuffer object to zero, and then displays the ByteBuffer object in terms of records.

      clearByteBufferData(bBuf,"bBuf");

      showRecords(bBuf);

Listing 10

The code in Listing 10 produces the output shown in Figure 3.

Clear bBuf
Records
  0 0.0
  0 0.0

Figure 3

(There is a space at the beginning of each record because a char value of zero doesn't represent a printable character.)

Read the file and display the data

The code in Listing 11:

  • Gets a FileChannel object for input for the disk file named junk.txt
  • Reads the data from the disk file into the ByteBuffer object
  • Closes the input stream and the FileChannel object
  • Displays the number of bytes read, along with the size of the disk file
  • Displays the records read into the ByteBuffer object
      //Get FileChannel for input
      iStr = new FileInputStream(
                           "junk.txt");
      fileChan = iStr.getChannel();

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

Listing 11

The output produced by the code in Listing 11 is shown in Figure 4.

Bytes read = 14
File length = 14
Records
A 14 0.33333334
B 28 0.6666667

Figure 4




Page 2 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel