Detecting File Download Completion

Hi! I would just like to ask if it’s possible for me to check the status of a file download using jsp/javascript.
I have a jsp page with a button, which when clicked, opens a ‘Save As’ dialog box for downloading a file from the server (file content is retrieved from db). I want to refresh or redirect my page after the download is complete. Is that doable?

Thanks in advance, any help will be greatly appreciated. :slight_smile:

In my opinion, I don’t think there’s a way to redirect a page after a file download. I don’t think there’s any browser event to trigger that in JavaScript. If there is, let us know.

^Ok, thanks sg707 :slight_smile:

Hello again, according to another forum I visited, it is indeed possible to detect if a file has finished downloading – from the server side.


ServletOutputStream op = response.getOutputStream();
File f = new File(String.valueOf(dirPath).concat(String.valueOf(filename)));
int length = 0;
response.setContentType("application/unknown");
response.setContentLength((int)f.length());
response.setHeader("Content-Disposition", String.valueOf(String.valueOf("attachment; filename=\\"").concat(String.valueOf(filename))).concat(String.valueOf("\\"")));
		
byte[] bbuf = new byte[10240];
DataInputStream in = new DataInputStream(new FileInputStream(f));
while (in != null) {
      if ((length = in.read(bbuf)) == -1)
          break;
      op.write(bbuf, 0, length);	
}
System.out.println("out of loop");	
in.close();
op.flush();
op.close();

Supposedly, the file download will be completed as soon as the while loop is exited. However, I’m getting different results depending on the size of the file.
The above code works perfectly with very large files (i.e. “out of loop” is only printed after download is complete). But when the file size is small, the “out of loop” string is printed even before I click ‘Save’ in the File Download dialog.

What is wrong here? Please help… :sick:

That would be recording the point at which the file has been fully buffered ready to send by the server rather than when it is fully received by the client. A small file that fits entirely in the buffer therefore can end up in the buffer ready to send before the download is requested while a larger file will only load as much as will fit the buffer and will only reload the buffer once that part of the file content has been sent. The end of loop will therefore trigger once the portion of the file still to be sent is small enough to fit the buffer rather than when the entire file is received by the client. If you can work out how big the buffer is you could add a delay for that amount of time you assume it would take to send that much data and then you will come very close to getting it right for files bigger than the buffer.

As there is no way to tell when the person clicks on the download button to start downloading from the buffer you can’t do much about determining when files smaller than that finish downloading.

Thanks for the explanation felgall! Follow up question though, what about the buffer I created:

byte[] bbuf = new byte[10240];

I’m not sure, is that different from the buffer you mentioned in your post? Will it help if I make the size smaller?

Will it also have an effect if I change the buffer size of the response? As in response.setBufferSize(int)?

I am not really familiar enough with Java and the exact way that downloading of files is handled to be able to answer that. You could try changing the size and see what effect it has, it isn’t a really big change to be able to undo if it doesn’t help and it should be easy enough to test. You could even test if that size has an effect without changing it by simply testing two files one slightly smaller and one slightly bigger than that size and see if that is the boundary.

Ok, so I tried playing around with sizes of the response buffer and byte … but the behavior of my program is still the same. :frowning:

Is it safe to say there isn’t a surefire way for me to implement what I’m trying to do?

You do detect that file has been downloaded but how would you refresh the page?

I think the client side action of refreshing/redirecting could be done by having javascript or some other client side code poll the webserver asking if a given download id is done. Do the download in a seperate window or iframe.

But yeah, I don’t think this will be reliable. Even if you manage to find out when the last byte has left your webserver, you don’t know when it has reached the client. There may be proxy servers and other forms of buffering in between. You might be able to guess correctly most of the time if you guess conservatively.

You might be able to cheese a multipart mime message, having the first part be the download file, and the second part be an html message which redirects.

creative solution! Use AJAX to check the status and redirect. As you said, it’s not 100% but fairly close.

Thanks crmalibu. :slight_smile: And yup, I’m actually using an iframe for the download part.

So like what felgall said, it isn’t possible at all for me to determine when exactly the file was fully received by the client, right? :frowning:

Thanks sg707, I’ve no prior experience with ajax but I’ll try to look into it. :slight_smile:
But if I use it, I would still have the same problem with determining download completion for smaller sized files, won’t I?

The only thing I can think of that would positive they have received it is if you could get a multipart mime message to work. I tried it real quick and firefox is ok with it(it actually worked lol), but opera, ie, and chrome barfed. Maybe I didn’t format it right, but I have a feeling this probably wouldn’t be reliable across browsers and platforms.

@crmalibu, Can you elaborate on the multipart mime message? I’m sorry but I’ve no idea where to start with that… Maybe you can show me some lines of code or something? Thanks :slight_smile:

An http response like this


HTTP/1.1 200 OK
MIME-Version: 1.0
Connection: close
Content-Type: multipart/mixed; boundary="foo123"

--foo123
Content-type: application/octet-stream
Content-Disposition: attachment; filename="pic.jpg"

(binary stuff here)
--foo123
Content-type: text/html

<meta http-equiv="refresh" content="3;url=http://google.com/">
--foo123--

^How do I create a response like that? :confused: My code in my servlet is:


ServletOutputStream op = response.getOutputStream();  
File f = new File(String.valueOf(dirPath).concat(String.valueOf(filename)));
int length = 0;
response.setContentType("application/unknown");
response.setContentLength((int)f.length());
response.setHeader("Content-Disposition", String.valueOf(String.valueOf("attachment; filename=\\"").concat(String.valueOf(filename))).concat(String.valueOf("\\"")));
		    
byte[] bbuf = new byte[10240];
DataInputStream in = new DataInputStream(new FileInputStream(f));
while (in != null) { 
      if ((length = in.read(bbuf)) == -1)
          break;
      op.write(bbuf, 0, length);	
}
System.out.println("out of loop");	    
in.close();
op.flush();
op.close();

Am I supposed to add more headers to manipulate the response?

edit:
And a follow up question: Is it possible for me to know the path of the local directory where the client chose to save the downloaded file?

“Is it possible for me to know the path…”

Absolutely not.

Thanks :slight_smile:

Hey, Hi fedfan,
Have you got any answer for this issue??
I am also facing the same problem.
Please reply in case you got any solution.

thanks in advance

^PritishS, this was a long time ago but if I remember correctly, I wasn’t able to come up with a foolproof method to do this… good luck, though :slight_smile: