Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java - Transferring big files over channels - NIO

Tags:

java

nio

I have to transfer ~100MB of data over ServerSocket using NIO, but I can't figure out how to do this without transfer breaking at any place / keeping the state of transfer.

My first idea was to send the size of file, apparently I can't send size of that big files because it wont even fit on RAM at once. Then I thought, why not just transfer til nothing is received, but thats when problem comes in.

Even if I am writing server-sided data all the time

        FileChannel fc = new FileInputStream(f).getChannel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        while(fc.read(buffer) > 0) {
            buffer.flip();
            while(channel.write(buffer) > 0);
            buffer.clear();
        }

but because there have to be breaks in file transfer some time reading the data constantly and breaking when nothing is available was bad idea.

I can't figure out how could I possibly tell the client if theres still data available without having to send each slice of data as new packet with opcode etc., or is it even possible?

I am also wondering if theres better way to send whole buffer than below

while(channel.write(buffer) > 0);
like image 468
Ruuhkis Avatar asked May 20 '12 20:05

Ruuhkis


2 Answers

Maybe you are looking for this:

channel.transferFrom(0, fc.size(), fc);
like image 166
Hakan Serce Avatar answered Nov 05 '22 15:11

Hakan Serce


The correct way to copy channels via buffers is as follows:

while (in.read(buffer) >= 0 || buffer.position() > 0)
{
  buffer.flip();
  out.write(buffer);
  buffer.compact();
}

This takes care of all the corner cases including read length != write length and having data left over at the end of the input.

NB that is for blocking mode. If you are in non-blocking mode you should return to the select() loop if read() or write() returns zero.

like image 25
user207421 Avatar answered Nov 05 '22 15:11

user207421