July 30, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

An Introduction to Java NIO and NIO.2

  • September 9, 2009
  • By Thribhuvan Thakur
  • Send Email »
  • More Articles »

FileChannel

A FileChannel is a specialization for reading, writing and manipulating a file (directory operations).

The following are some of the capabilities of a FileChannel:

  • Mapping a region of a file directly into memory (efficient for large files)
  • Interacting with file system locks
  • Transferring bytes between the channels more efficiently without the application code having to use buffers and looping.

The following UML shows the most significant methods excluding scattering and gathering behavior.


Figure 2. FileChannel

Since there is no open() method in FileChannel to open a channel (prior to NIO.2), you could use Java I/O streams to associate a file channel as shown in the example below:

  //open the files using the old fashioned way -- streams
  FileInputStream fsin = new FileInputStream(srcFileName);
  FileOutputStream fsout = new FileOutputStream(trgtFilename);
  RandonAccesFile raf = new RandomAccessFile(someFilename, "rw")
  
  //retrieve the respective channels using getChannel method
  FileChannel fcin = fsin.getChannel();
  FileChannel fcout = fsout.getChannel();
  FileChannel fcran = raf.getChannel();

A FileChannel is capable of transferring bytes between the channels directly or when marshaled within a ByteBuffer. It is important to size the ByteBuffer appropriately to the underlying operating system block size for optimum performance.

Let's look at some of the important methods of a FileChannel:

position() Similar to a Buffer, FileChannel also has a file position that marks the current position from the beginning of the file. A read or write operation on this file updates the position.

position(newPosition) Slides the file position similar to RandomAccessFile.seek(). You could set the position greater than the file's current size, but it does not change the size of the file, unless you write to the file at the new position.

truncate(newSize) Shrinks the file-- if the given size is greater than or equal to the file's size then the file is not modified. Otherwise the file length is set to the new size.

transferTo() Copies bytes from the channel the file is associated with to a given writeable channel directly without the use of buffers.

transferFrom() Copies bytes into the channel the file is associated with from a given readable channel directly without the use of buffers.

The behavior of the transferTo()/transferFrom is dependent upon the host operating system, as noted in the Javadoc entry:

"Many operating systems can transfer bytes directly from the source channel into the filesystem cache without actually copying them."

map (FileChannel.MapMode, position, size) A convenient way to map a region of the channel's data file into a direct byte buffer (MappedByteBuffer) so that you could change the byte order, access file data, or translate the data using methods like asIntBuffer().

The MappedByteBuffer returned by this method will have a position of zero and a limit and capacity of size; its mark will be undefined.

I/O from MappedByteBuffer implies fetching bytes from the file and writing the buffer stores bytes directly into the file, avoiding system call overhead or buffer copies.

  //open the files using the old fashioned way -- streams
  RandomAccessFile rwf = new RandomAccessFile(someFilename, "rw")
  RandomAccessFile rof = new RandomAccessFile(someFilename, "r")
  
  //retrieve the respective channels using getChannel method
  FileChannel fchrw = rwf.getChannel();
  FileChannel fchr  = rof.getChannel();
  
  //map the file to the buffer -- creates read-write buffer
  MappedByteBuffer mbb = fchrw.map(FileChannel.MapMode.READ_WRITE, 0, fc.size);
  //map the file to the buffer -- creates read-only buffer
  MappedByteBuffer mbb = fchrw.map(FileChannel.MapMode.READ_WRITE, 0, fc.size);
  
  //do any data translation needed since MappedByteBuffer extends ByteBuffer

read(ByteBuffer) copies bytes from the file into the buffer. The file position is updated with number of bytes read.

write(ByteBuffer) copies bytes from the buffer to the file. The file position is updated with the number of bytes written. If the file is in append mode, the position is first advanced to the end of the file before writing to the file.

The following is an example of read/write methods that copy files using a direct buffer as well as transferTo() methods:

  //open the files using the old fashioned way -- streams
  File inFile = new File("C:/SourceFile.java"); // pick some arbitrary java file 
  File transferFile = new File("C:/TransferFile.txt");
  File copyFile = new File("C:/SourceFileCopy.txt ");
  
  //retrieve the respective channels using getChannel method
  FileChannel fcin = new RandomAccessFile(inFile, "r").getChannel();
  FileChannel fcoutTransfer = new RandomAccessFile(transferFile, "rw").getChannel();
  FileChannel fcoutCopy = new RandomAccessFile(copyFile, "rw").getChannel();
  
  //use transferTo method to copy 
  Long bytesTransferred = fcin.transferTo(0, fcin.size(), fcoutTransfer);
  
  //allocate buffer -- use the right size by experimenting with different sizes
  ByteBuffer buffer = ByteBuffer.allocateDirect(1024); //direct buffer
  
  long size = fcin.size(), n=0;
  
  //time to play the old game - clear, read, flip and write
  while( n<size ) {
   buffer.clear(); //makes the buffer ready by resetting the pointers
   if( fcin.read(buffer) < 0 ) //fill the buffer by reading from channel
    break;
   buffer.flip(); //makes the buffer writing the data just read
   n+= fcout.write(buffer);
  }
  //close the resources
  fcin.close(); fcoutTransfer.close();fcoutCopy.close();

lock() This method blocks until an exclusive lock is acquired, returning a FileLock object. If the channel is closed, or the invoking thread is interrupted, this method gives up trying to acquire the lock and throws the appropriate exception. Regions of a file can be blocked by calling lock(position, size, shared), whose parameters specify the position at which the locked region is to start, the size of the locked region and whether the lock is shared or exclusive.

The behavior of the file lock is dependent upon the host operating system, as noted in the Javadoc entry:

"Some operating systems do not support shared locks, in which case a request for a shared lock is automatically converted into a request for an exclusive lock ……. File locks are held on behalf of the entire Java virtual machine. They are not suitable for controlling access to a file by multiple threads within the same virtual machine".

  //open the files using the old fashioned way -- use File object
  File file = new File(filename);
  
  //retrieve the respective channels using getChannel method
  FileChannel fcin = new RandomAccessFile(file, "rw").getChannel();
   
  //lock the file 
  FileLock lock = cin.lock(); // this method blocks until it can fetch the lock
  lock.release();
  lock = cin.tryLock(0, file.size(), true);//try acquiring the lock without blocking  
  lock.isShared(); //if the lock is shared or exclusive


Tags: Java, content, upgrading



Page 2 of 3



Comment and Contribute

 


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

 

 


Sitemap | Contact Us

Rocket Fuel