Search code examples
javaniofilechannel

Why FileChannel reading never ends?


When I execute following class

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

public class FileChannelTest {                                                                                                                      
    public static void main(final String... args) throws IOException {                                                                              
        final File file = File.createTempFile("temp", null);                                                                                        
        file.deleteOnExit();                                                                                                                        
        // write some                                                                                                                               
        try(OutputStream output = new FileOutputStream(file)) {                                                                                     
            output.write(new byte[128]);                                                                                                            
            output.flush();                                                                                                                         
        }                                                                                                                                           
        System.out.println("length: " + file.length());                                                                                             
        // read to end                                                                                                                              
        try(FileChannel channel                                                                                                                     
            = FileChannel.open(file.toPath(), StandardOpenOption.READ)) {                                                                           
            final ByteBuffer buffer = ByteBuffer.allocate(128);                                                                                     
            for(int read; (read = channel.read(buffer)) != -1; ) {                                                                                  
                System.out.println("read: " + read);                                                                                                
            }                                                                                                                                       
        }                                                                                                                                           
    }                                                                                                                                               
}

The reading loop never ends.

$ java -version
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)
$ java FileChannelTest.java
$ java FileChannelTest
length: 128
read: 128
read: 0
read: 0
read: 0
...
...
...

FileChannel.read(ByteBuffer) says,

Reads a sequence of bytes from this channel into the given buffer. Bytes are read starting at this channel's current file position, and then the file position is updated with the number of bytes actually read. Otherwise this method behaves exactly as specified in the ReadableByteChannel interface.

What does Otherwise mean?


Solution

  • When you read into a ByteBuffer, it can only read as many bytes as is available in the buffer i.e. byteBuffer.remaining() This means once the buffer is full, when you do a read it returns 0.

    I suggest you use either clear() if you have consumed all the data read, or compact() if you have consumed only a portion of the data read.

          for(int read; (read = channel.read(buffer)) != -1; ) {                                                                                  
                System.out.println("read: " + read);    
                buffer.clear(); // so we can read more data                                                                                           
          }