transferFrom returns 0 before end of channel is reached

Hey, I have this code for downloading a file via HTTP and it mostly works fine. However this crashes for a friend of mine with a very poor network connection (“mobile internet”, 2-10kb/s download speed) because transferFrom() returns 0 before the full file is downloaded (eg. downloaded 2327 / 3163 bytes). I know the filesize in advance, however I don’t want to loop until the received amount = expectedSize because if I modify the file while someone is downloading it they’ll get stuck in an infinite loop. Anyone know how I can fix this?

Thanks,
roland


try
{
	URL fileURL = new URL(urlOfFileToDownload);
	InputStream stream = fileURL.openStream();
	
	ReadableByteChannel rbc = Channels.newChannel(stream);
	if (!fileExists(saveLocation))
		createEmptyFile(saveLocation);
	FileOutputStream fos = FileManager.GetFileOutputStream(saveLocation);
	int totalNumBytesTransferred = 0;
	int bytesTransferred = 0;
	do
	{
		bytesTransferred = (int)fos.getChannel().transferFrom(rbc, totalNumBytesTransferred, TRANSFER_CHUNK_SIZE); //TRANSFER_CHUNK_SIZE=512*1024
		totalNumBytesTransferred += bytesTransferred;
	} while (bytesTransferred > 0);
	
	fos.close();
	
	//check file
	if (totalNumBytesTransferred != expectedFileSize) //I know expectedFileSize
		throw new UnsupportedOperationException("Failed to fully download file " + urlOfFileToDownload +": wrong filesize (expected " + expectedFileSize +", received "+totalNumBytesTransferred);
	
	success = true;
}
catch(Exception e)
{
	error = e.getMessage();
	e.printStackTrace();
}

Well first off, wouldn’t that loop already cause an infinite loop? You’re looping through the code so long as you’ve received bytes, which could go on forever. Is this actually working? Because it shouldn’t!

You should make it like you said, receivedAmount==ExpectedAmount;

You should also make a

long = System.getCurrentTimeMillis()

of when last bytes where received.

If last bytes were received from more than N amount of time, kill the loop, and say to the user that connection has been lost, or some kind of error happened. Basically make a kill switch that would kill your loop if no bytes were received for N amount of time. (N should be time that would allow for some lag, but not big enough that user would get annoyed by looking at stuck UI)

Thanks :slight_smile: I’ll try that and let you know how it goes.

It can’t go on forever because the filesize is fixed :slight_smile:

I thought I would try to make an easier explanation.

I received 0 bytes. Since I received 0 bytes, I will wait for 10 seconds. If I don’t receive bytes > 0 after 10 seconds, I will kill the loop and say that I fucked up.

I got your other one fine, but thanks anyway ;D