I use NSURLConnection to download large files from the web on iPhone. I use the "didReceiveData" method to append data to a file in the Documents folder. It works fine.
If the download is interrupted (for instance, because the user pressed the "home" button), I would like to be able to continue to download the next time the user launch my application, and not from scratch!
Anyone can help me ?
ASIHTTPRequest has easy to use support for resuming downloads:
http://allseeing-i.com/ASIHTTPRequest/How-to-use#resume
Alternatively, find out how much data you have downloaded already by looking at the size of the existing data, and set the 'Range' header on your NSMutableURLRequest:
[request addValue:#"bytes=x-" forHTTPHeaderField:#"Range"];
..where x is the size in bytes of the data you have already. This will download data starting from byte x. You can then append this data to your file as you receive it.
Note that the web server you are downloading from must support partial downloads for the resource you are trying to download - it sends the Accept-Ranges header if so. You can't generally resume downloads for dynamically generated content (e.g. a page generated by a script on the server).
The only method I can think of is to break the file you're downloading up into smaller files. You can use the
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
method to determine when each portion of the file is finished, and restart the download at the last portion that didn't get downloaded.
Look at the HTTP standard to see how you would form a request to start a transfer of a resource from a specific offset. I can't find any code offhand, sorry.
Related
How to download or view the files sent as multi-part Request (e.g. PUT) via a software tool?
Is there any way to accomplish this with a specific tool like CharlesProxy on macOSX, to download and view files that were sent as a part of request (PUT multipart request)? I typically fix such issues by saving the file to sandbox via code changes. Ideally, need something that can be used by our QA and doesn't require any code modification.
Charles Proxy on macos is sufficient for the most dev/QA needs, such as:
Throttle network
Device debugging
Download response data
...
However, there is no option present to view or download files in HTTP request in Charles Proxy 4.x:
Charles Proxy 4.x (and earlier) allows saving response files, example pdf in this screenshot:
This can be done by editing binary file manually. It's a bit tricky, but can save the file in multipart HTTP request, without any modification to project code.
Here are the steps (verified on Charles v4.2.8 and macOS v10.12.6):
Save request. Right click a recorded HTTP request (the one that send file), and click "Save Request...". This will save the whole HTTP request in binary format.
Inspect Hex representation of request. Left click that recorded HTTP request, and click "Hex" tab of "Request" panel. This will show the binary representation of request, together with some parsed text.
Edit the saved request. Open the saved request (step 1) with editor that support binary, such as Sublime Text. Then, remove all non-image binary code according to the result of step 2. Especially, remove every bytes before (and include) the first empty line (0d0a0d0a in macOS and Windows, 0a0a in Linux), and remove the tail bytes. For example, following screenshot indicates request bytes of step 2, the selected bytes would be deleted (please note the 0d0a bytes, as this experiment is taken on Mac):
...
Save image file. Save the file after step 3 is finished. Then, append filename extension according to the Content-Type value in step 2. In this experiment, the Content-Type is image/png, so .png is appended to the filename.
That's it. You can open the xxx.png file now. It's a pure image file.
Note: this experiment only contain 1 file, but the strategy works when there are multiple file upload in request.
I have a ajax download functionality in my MVC webapp.
User can select a criteria and click on export button. Internally it will fetch data and return an Excel file. up to this functionality is working fine.
But the issue occurs, While one download process is running and now user changes the filter criteria and again click on export button. Now two download processes are running. Whichever process completes first will return file to download. Now the user can see Open, save, cancel option to download first file. As this stage when second download request is also completed and returns file to download. When I opens one file the another file download option is also lost.
Initially I thought it might because both the files are having same name. So I made changes to set unique file name for every request. But It still gives only single file to download.
Can anyone help me on this?
edited :
On other pages where I have two different types of files to download, the above functionality works successfully.
In none ajax requests, page can only be waiting for one response.
In order to solve that problem and wait for multiple responses you should use target attribute with value "new" as the following code depicts:
Your download Text
The above code makes each response to be downloaded in a new tab.
I am downloading a mp4 file with my iOS app, it works fine using
NSData dataWithContentsOfURL
but i need to updated only if the file has been updated,
can I check the file headers? or what is the best way to determine if the file has been updated so I downloaded it again?
Thanks
You can access the metadata using the http HEAD request, as explained in this SO answer. You'll need to create some sort of parser to pick out the information you need, though. Note that this might not work with every server, depending on how it has been set up.
If you have control of the server yourself, I'd recommend using a php script to output the date the file has been last changed, which you would call before downloading the file.
Personally, I prefer placing a manifest file (usually a plist) alongside the file in question, as it can hold even more data, for example metadata for several files, the number of entries in a database and the like. A backdraw of this approach is that you'll need to keep this file up to date, though. But often, that is worth the while.
Lastly, as rckoenes has mentioned, dataWithContentsOfURL is not a very good way to download files, espcially large ones. You really should be using some sort of datamanager class, which manages a NSURLConnection.
I'm developing a download manager using Indy and Delphi XE (The application uses Multithreading to attempt several connections to the server). Everything works fine but sometimes the final downloaded file is broken and when I check downloaded temp files I see that 2 or 3 of them is filled with zero at their end. (Each temp file is download result of each connection).
The larger the file is, the more broken temp files I get as the result.
For example in one of the temp files which was 65,536,000 bytes, only the range of 0-34,359,426 was valid and from 34,359,427 to 64,535,999 it was full of zeros. If I delete those zeros, application will automatically download the missing segments and what I get as the result, well if the problem wouldn't happen again, is the healthy downloaded file.
I want to get rid of those zeros at the end of the temp files without having a lost in download speed.
P.S. I'm using TFileStream and I'm sending it directly to TIdHTTP and downloading the files using GET method.
Additional Info: I handle OnWork event which assigns AWorkCount to a public int64 variable. Each time the file is downloaded, the downloaded file size (That Int64 variable) is logged to a text file and from what the log says is that the file has been downloaded completely (even those zero bytes).
Make sure the server actually supports downloading byte ranges before you request a range to download. If the server does not support ranges, a requested range will be ignored by the server and the entire file will be sent instead. If you are not already doing so, you should be using TIdHTTP.Head() to text for range support before then calling TIdHTTP.Get(). You also need to do this anyway to detect if the remote file has been altered since the last time you downloaded it. Any decent download manager needs to be able to handle things like that.
Also keep in mind that if TIdHTTP knows up front how many bytes are being transferred, it will pre-allocate the size of the destination TStream before then downloading data into it. This is to speed up the transfer and optimize disc I/O when using a TFileStream. So you should NOT use TFileStream to access the same file as the destination for multiple simultaneous downloads, even if they are writing to different areas of the file. Pre-allocating multiple TFileStream objects will likely trample over each other trying to set the file size to different positions. If you need to download a file in multiple pieces simultaneously then either:
1) download each piece to a separate file and copy them into the final file as needed once you have all of the pieces that you need.
2) use a custom TStream class, or Indy's TIdEventStream class, to manage the file I/O yourself so you can ignore TIdHTTP's pre-allocation attempts and ensure that multiple file I/O operatons do not overlap each other incorrectly.
I'm having trouble working on FileReference download(URL) function. I needed to automatically download the files in a particular space on my harddisk but the SAVE AS dialog always displays. can I make it automatically download in a certain place on my disk?
I'm going to assume "automatically download" means "save" here. Nope, If you use FileReference (or File in AIR), there's no way to automatically save without showing the Save As dialog box.
If you don't need to access the file outside of the app, then take a look at the SharedObject class: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/SharedObject.html. By default you can create SharedObjects of up to 100KB without needing the client's permission (see the description of getLocal()), which should be fine for more simple text or xml info - you can compress it using ByteArray if you want to save space. Any more than that and a small dialog will open asking permission. Once you've given permission however, it won't ask again.