6.4 File Copying with Buffers

Example 6-4 is another file copying program. Instead of using the shortcut FileChannel.transferTo( ) method, this example defines a generic copy( ) method for copying bytes from one channel to another and demonstrates the basic java.nio I/O loop, described here:

  1. The buffer is filled with bytes from one channel.

  2. The buffer is flipped, making it ready to be drained. See Buffer and Buffer.flip( ) for details.

  3. The buffer is drained by writing bytes from it to another channel.

  4. The buffer is compacted, discarding bytes that have been drained from it and shifting remaining bytes to the beginning of the buffer. As part of this process, the current position of the buffer is reset to point to the first available byte in the buffer, making the buffer ready to be filled again. See ByteBuffer.compact( ) for details. If the call to write( ) completely drained the buffer, then clear( ) can be used instead of compact( ).

This loop continues until the input channel indicates that there are no more bytes to read (its read( ) method returns -1) and the buffer is empty.

Variants on this basic loop appear in most programs that use the New I/O API, so it is important to understand it. For clarity, Example 6-4 omits exception-handling and stream-closing code so that you can focus on the basic loop.

Example 6-4. FileCopy3.java
package je3.nio; import java.io.*; import java.nio.*; import java.nio.channels.*; public class FileCopy3 {     public static void main(String[  ] args) throws IOException {         // Open file streams and get channels for them.         ReadableByteChannel in = new FileInputStream(args[0]).getChannel( );         WritableByteChannel out;         if (args.length > 1) out = new FileOutputStream(args[1]).getChannel( );         else out = Channels.newChannel(System.out);         // Do the copy         copy(in, out);                  // Exception-handling and stream-closing code has been omitted.     }     // Read all available bytes from one channel and copy them to the other.     public static void copy(ReadableByteChannel in, WritableByteChannel out)         throws IOException      {         // First, we need a buffer to hold blocks of copied bytes.         ByteBuffer buffer = ByteBuffer.allocateDirect(32 * 1024);         // Now loop until no more bytes to read and the buffer is empty         while(in.read(buffer) != -1 || buffer.position( ) > 0) {             // The read( ) call leaves the buffer in "fill mode".  To prepare             // to write bytes from the buffer, we have to put it in "drain mode"              // by flipping it: setting limit to position and position to zero             buffer.flip( );              // Now write some or all of the bytes out to the output channel             out.write(buffer);             // Compact the buffer by discarding bytes that were written              // and shifting any remaining bytes.  This method also              // prepares the buffer for the next call to read( ) by setting the             // position to the limit and the limit to the buffer capacity.             buffer.compact( );         }     } }

6.4.1 Loop Alternatives

The code shown in Example 6-4 isn't the only way to express the basic java.nio channel copying loop. Following are two variants from the book Java NIO, by Ron Hitchens (O'Reilly). The first variant simplifies the exit condition for the loop, by adding a second loop to drain the buffer when the first loop reaches end-of-file:

public static void copy1(ReadableByteChannel in, WritableByteChannel out)     throws IOException {     ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);          while(in.read(buffer) != -1) {         // Prepare the buffer to be drained         buffer.flip( );                  // Write to the channel; may block         out.write(buffer);                  // If partial transfer, shift remainder down         // If buffer is empty, same as doing clear( )         buffer.compact( );     }          // EOF will leave buffer in fill state     buffer.flip( );          // Make sure that the buffer is fully drained     while (buffer.hasRemaining( )) {         out.write(buffer);     } }

The second variant of the loop ensures that the buffer is fully drained on each iteration, so that the call to compact( ) is no longer necessary:

public static void copy2(ReadableByteChannel in, WritableByteChannel out)     throws IOException {     ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);          while(in.read(buffer) != -1) {         // Prepare the buffer to be drained         buffer.flip( );                  // Make sure that the buffer was fully drained         while (buffer.hasRemaining( )) {             out.write(buffer);         }                  // Make the buffer empty, ready for filling         buffer.clear( );     } }


Java Examples in a Nutshell
Java Examples in a Nutshell, 3rd Edition
ISBN: 0596006209
EAN: 2147483647
Year: 2003
Pages: 285

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net