TheFileChannel is a Java NioChannel implementation for working with a file. It facilitates reading, writing, mapping and manipulating a file.
The examples in this tutorial will be demonstrated via test cases with no explicit Charset specified when encoding and decoding text fromByteBuffers.
1. Introduction
TheFileChannel has a rich hierarchy of interfaces extending to it a diverse set of behaviors and provides a handle to access a rich set of meta data properties of the file including time stamps for creation, modification, size etc.
FileChannels are safe for multi-threaded use and will allow certain operations (those that use explicit positions) to execute concurrently while those that involve the intrinsicpositionmarker will execute serially.
The view of the underlying file is guaranteed to be consistent with other views of the same file within the same Java process (Threads) but the same guarantee is not extended to other concurrently executing programs.
AFileChannel is created by executing one of theopen(..)methods of theFileChannel class or by callinggetChannel(...) on any eitherFileInputStream,FileOutputStream orRandomAccessFile. Thepositionmarker of theFileChannel and ultimately the state of theFileChannel is coupled to the state of the class on whichgetChannel(...)was called.
Opening aFileChannel via one of theopen(...)methods allows for the provision of a mode in which theChannel is opened. This is encapsulated very nicely for us via the StandardOpenOption enumeration.
If we obtained theFileChannel via thegetChannel(...)method ofFileInputStream then theFileChannel is opened for reading and will throw a NonWritableChannelException if you attempt to write to it, the same bodes for opening aFileChannel with aStandardOpenOption#READ and attempting to write to it. If we obtained aFileChannel via thegetChannel(...)method ofFileOutputStream then theFileChannel is opened for writing and reading. We need to be explicit about ourStandardOpenOption’s when getting aFileChannel via one of theopen(...)methods.
2. Technologies used
The example code in this article was built and run using:
- Java 1.8.101 (1.8.x will do fine)
- Maven 3.3.9 (3.3.x will do fine)
- Spring source tool suite 4.6.3 (Any Java IDE would work)
- Ubuntu 16.04 (Windows, Mac or Linux will do fine)
3. Reading
Reading from a FileChannel
@Test public void viaFileInputStream() throws IOException { final StringBuilder data = new StringBuilder(); final FileInputStream fis = new FileInputStream(new File(SRC)); try (FileChannel channel = fis.getChannel()) { readFromChannel(channel, data); } finally { if (!Objects.isNull(fis)) { fis.close(); } } assertEquals("Invalid content", CONTENTS.toString(), data.toString().trim()); } @Test public void readOk() throws IOException { final StringBuilder data = new StringBuilder(); try (FileChannel channel = FileChannel.open(Paths.get(SRC), StandardOpenOption.READ)) { readFromChannel(channel, data); } assertEquals("Invalid content", CONTENTS.toString(), data.toString().trim()); } @Test(expected = NoSuchFileException.class) public void readNoSuchFile() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); try (FileChannel channel = FileChannel.open(Paths.get("/tmp/nosuchfile.txt"), StandardOpenOption.READ)) { channel.read(buffer); } } @Test(expected = NonWritableChannelException.class) public void tryWrite() throws IOException { try (FileChannel channel = FileChannel.open(Paths.get(SRC), StandardOpenOption.READ)) { channel.write(ByteBuffer.wrap("Trying to write this text".getBytes())); } } @Test(expected = NonWritableChannelException.class) public void tryWriteViaFileInputStream() throws IOException { final FileInputStream fis = new FileInputStream(new File(SRC)); try (FileChannel channel = fis.getChannel()) { channel.write(ByteBuffer.wrap("Trying to write this text".getBytes())); } finally { if (!Objects.isNull(fis)) { fis.close(); } } } private void readFromChannel(final FileChannel channel, final StringBuilder data) throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); int bytes = channel.read(buffer); while (bytes >= 0) { if (bytes > 0) { transferTo(buffer, data); } buffer.clear(); bytes = channel.read(buffer); } }- line 2: defines a method for obtaining aFileChannel from aFileInputStream and reading all the bytes from theFileChannel
- line 18: defines a method for obtaining aFileChannel via one of the static factory methods
open(...)on theFileChannel class and reading all the bytes from theFileChannel - line 28: defines a method for attempting to open and read a file that does not exist
- lines 37 & 44: define methods for attempting to write to aFileChannel that was opened exclusively for reading via theStandardOpenOption#READ or form calling
getChannel(...)on theFileInputStream - lines 56-67: defines a method for reading the bytes from aFileChannel into a finite sizedByteBuffer
4. Writing
Writing to a FileChannel
@Test public void viaFileOutuputStream() throws IOException { final ByteBuffer buffer = ByteBuffer.wrap(CONTENTS.getBytes()); final FileOutputStream fos = new FileOutputStream(new File(TARGET)); int bytes = 0; try (FileChannel channel = fos.getChannel()) { bytes = writeToChannel(channel, buffer); } finally { if (!Objects.isNull(fos)) { fos.close(); } } assertTrue("Invalid amount of bytes written", CONTENTS.getBytes().length == bytes); } @Test public void writeOk() throws IOException { final ByteBuffer buffer = ByteBuffer.wrap(CONTENTS.getBytes()); int bytes = 0; try (FileChannel channel = FileChannel.open(Paths.get(TARGET), StandardOpenOption.WRITE, StandardOpenOption.CREATE)) { bytes = writeToChannel(channel, buffer); } assertTrue("Invalid amount of bytes written", CONTENTS.getBytes().length == bytes); } @Test(expected = NoSuchFileException.class) public void writeNoSuchFile() throws IOException { try (FileChannel channel = FileChannel.open(Paths.get("/tmp/nosuchfile.txt"), StandardOpenOption.WRITE)) { } } private int writeToChannel(final FileChannel channel, final ByteBuffer buffer) throws IOException { int bytes = 0; while (buffer.hasRemaining()) { bytes += channel.write(buffer); } return bytes; }- line 2: defines a method that gets aFileChannel from aFileOutputStream and writes some content to theFileChannel
- line 19: defines a method that gets aFileChannel via the
open(...)method and writes some content to theFileChannel. TwoStandardOpenOption settings are specified indicating that the file should be created and that theFileChannel should be opened inwritemode - line 31: defines a method that attempts to write to a file that does not exist
- lines 36-43: defines a method that writes the contents of the givenByteBuffer to the givenFileChannel and returns the number of bytes that was written
5. Transferring
Transferring data between two FileChannels
@Test public void transfer() throws IOException { try (FileChannel in = FileChannel.open(Paths.get(SRC), StandardOpenOption.READ, StandardOpenOption.CREATE); FileChannel out = FileChannel.open(Paths.get(TARGET), StandardOpenOption.WRITE, StandardOpenOption.CREATE)) { long bytes = 0; while(bytes < in.size()) { bytes += out.transferFrom(in, bytes, in.size()); } out.force(true); assertTrue("All bytes not transfered", in.size() == bytes); } }line 2: defines a method that opens twoFileChannels, one for reading from and one for writing to. ThetransferFrom(...)method is called on the targetFileChannel which allows us to transfer all the bytes from the sourceFileChannel to the targetFileChannel. It’s important to do this in a loop as not all the bytes are guaranteed to be transferred in a single call.
ThetransferFrom(...)andtransferTo(...)methods exploit various OS optimizations (if available) and should probably be preferred when working with ReadableByteChannel andWritableByteChannel instances.

Thank you!
We will contact you soon.
6. Mapping
Mapping the contents of a File into memory
@Test public void mapReadonly() throws IOException { try (FileChannel channel = FileChannel.open(Paths.get(SRC), StandardOpenOption.READ)) { final MappedByteBuffer buffer = channel.map(MapMode.READ_ONLY, 0, channel.size()); byte[] tmp = new byte[buffer.remaining()]; buffer.get(tmp); assertTrue("Buffer not direct", buffer.isDirect()); assertEquals("Content does not match", CONTENTS.toString(), new String(tmp).trim()); } } @Test(expected = ReadOnlyBufferException.class) public void mapReadonlyBufferException() throws IOException { try (FileChannel channel = FileChannel.open(Paths.get(SRC), StandardOpenOption.READ)) { final MappedByteBuffer buffer = channel.map(MapMode.READ_ONLY, 0, channel.size()); buffer.putChar('x'); } } @Test public void mapWrite() throws IOException { try (FileChannel channel = FileChannel.open(Paths.get(SRC), StandardOpenOption.READ, StandardOpenOption.WRITE)) { final MappedByteBuffer buffer = channel.map(MapMode.READ_WRITE, 0, channel.size()); buffer.clear(); buffer.put(new StringBuilder(CONTENTS).reverse().toString().getBytes()); channel.force(true); } try (FileChannel channel = FileChannel.open(Paths.get(SRC), StandardOpenOption.READ)) { final MappedByteBuffer buffer = channel.map(MapMode.READ_ONLY, 0, channel.size()); byte[] tmp = new byte[buffer.remaining()]; buffer.get(tmp); assertEquals("Contents does not match reverse", new StringBuilder(CONTENTS).reverse().toString(), new String(tmp)); } }- line 2: defines a method that maps the contents (entire) of a file into memory in
read only mode. - line 15: defines a method that attempts to mutate a
MappedByteBufferthat was opened inREAD_ONLYmode - line 24: defines a method that hat maps the entire contents of a file into memory and mutates the contents of it in memory
This type of behavior is especially useful with large files where a portion of a file (specified by byte ranges) can be mapped into memory and utilized at any given point in time. TheFileChannel.MapMode specifies the following modesPRIVATE READ_ONLY READ_WRITE which need to correlate with theFileChannelsStandardOpenOption mode otherwise aNonWritableChannelException or aNonReadableChannelException will be raised.
TheMapMode in concert with theStandardOpenOptions allow finer granularity with permissible operations when mapping a files contents into memory.
7. Locking
Taking out a lock on a file region
@Test public void exclusiveLock() throws IOException { try (FileChannel channel = FileChannel.open(Paths.get(SRC), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); FileLock lock = channel.lock();) { assertTrue("Lock is not exclusive", !lock.isShared()); } } @Test public void sharedLock() throws IOException { try (FileChannel channel = FileChannel.open(Paths.get(SRC), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); FileLock lock = channel.lock(0, channel.size(), true)) { assertTrue("Lock is not shared", lock.isShared()); } } @Test(expected = OverlappingFileLockException.class) public void testOverlappingLock() { final CountDownLatch innerThreadLatch = new CountDownLatch(1); final CountDownLatch testThreadLatch = new CountDownLatch(1); try (FileChannel channel = FileChannel.open(Paths.get(SRC), StandardOpenOption.WRITE, StandardOpenOption.CREATE)) { new Thread() { public void run() { try { channel.lock(); innerThreadLatch.countDown(); testThreadLatch.await(); } catch (OverlappingFileLockException | IOException | InterruptedException e) { throw new RuntimeException("Unable to get lock on file for overlapping lock test", e); } } }.start(); innerThreadLatch.await(); channel.lock(); } catch (InterruptedException | IOException e) { throw new RuntimeException(e); } finally { testThreadLatch.countDown(); } } @Test public void lockDifferentRegions() throws IOException { try (FileChannel channel = FileChannel.open(Paths.get(SRC), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); FileLock lock1 = channel.lock(0, 5, true); FileLock lock2 = channel.lock(5, channel.size(), true)) { assertFalse("Locks same", lock1 == lock2); } } @Test(expected = OverlappingFileLockException.class) public void overlappingLockSameThread() throws IOException { try (FileChannel channel = FileChannel.open(Paths.get(SRC), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE); FileLock lock1 = channel.lock(0, channel.size(), true); FileLock lock2 = channel.lock(0, channel.size(), true)) { } }- line 2 & 10: defines a method for testing the
sharedproperty of aFileLock - line 18 & 55: defines a method for testing for anOverlappingFileLockException from different and the same Threads
- line 46: defines a method for showing that two differentFileLocks can be taken out on two different regions (byte range) of the same file
An aside aboutFileLocks. Strictly not to be used as a sole means of concurrency in the JVM, however in concert with normal synchronization measures can prove effective when trying to control file region access. Inside a JVM process no twoFileLocks can lock the same region.
FileLocks can be exclusive or shared:
- Exclusive: prevents other processes / threads from acquiring anyFileLock (shared or exclusive) on the same region of a file
- Shared: prevents other processes / threads from acquiring an exclusiveFileLock on the same region of a file but allows other processes / threads to acquire a sharedFileLock on the same region of a file
8. Test cases
The project is a maven project and can be run from the command line by executing the following:mvn clean install. Alternatively one can run the code from within Eclipse.
9. Summary
In this example we learnt how to read from a file via aFileChannel, how to write to a file via aFileChannel, how to map part of a file into memory from aFileChannel, how to transfer data from one file to another via aFileChannel and how to lock regions of a file from aFileChannel.
10. Download the Source Code
This was a Java Nio FileChannel Example
You can download the full source code of this example here:Java Nio FileChannel Example

Thank you!
We will contact you soon.



