Resumable File Downloader – Simple AIR app

This AIR application demonstrates how to download, pause and resume downloads of larger files(mp3, flv, etc) and save to the user’s computer. Big Thanks to Benjamin Dobler for his blog post Resumable Downloads with AIR.

Sample Files:
ResumableDownloader.air (AIR, 524 KB)

7 Comments


  1. vkwave
    April 13, 2010 at 9:48 am

    Dear Mariusz,
    Thank you very much for sharing your experience code. I was working on the same and also got help from http://richapps.de/?p=113.

    Thank you again to share your code.

  2. Aaron Hardy
    November 12, 2010 at 3:49 am

    Hey, thanks for the sample app. It’s got a bug though. You’ll notice if you pause/resume a few times the resulting file will not be as large as the original. The fix is to replace this:

    if(bytesTotal != event.bytesTotal)
    bytesTotal = event.bytesTotal;

    progressBar.setProgress( (totalBytesLoaded + event.bytesLoaded) / event.bytesTotal, progressBar.maximum);

    ————–

    with this:

    ————–
    if(bytesTotal == 0)
    bytesTotal = event.bytesTotal;

    progressBar.setProgress( (totalBytesLoaded + event.bytesLoaded) / bytesTotal, progressBar.maximum);

  3. Mariush T.
    November 13, 2010 at 1:25 pm

    Thank you Aaron for fixing it and sharing the code.

  4. sunny
    February 25, 2011 at 8:58 am

    When downloading large files will consume a lot of memory.
    I have fixed the problem.

    —————————————————————————

  5. sunny
    February 25, 2011 at 9:00 am

    import flash.events.Event;
    import flash.events.ProgressEvent;
    import flash.net.URLRequest;
    import flash.net.URLStream;
    import flash.utils.ByteArray;

    import mx.controls.Alert;
    import mx.events.FlexEvent;

    private var urlStream:URLStream;
    private var fData:ByteArray;

    private var bytesLoaded:Number = 0;
    private var totalBytesLoaded:Number = 0;
    private var bytesTotal:Number = 0;

    private var fileName:String = ”;
    private var file:File;

    private var fileStream:FileStream = new FileStream;

    protected function init(event:FlexEvent):void
    {
    urlStream = new URLStream;
    urlStream.addEventListener(ProgressEvent.PROGRESS, onProgress);
    urlStream.addEventListener(Event.COMPLETE, onComplete);
    fileInput.text = “http://10.10.10.21/mov/cats.avi”;
    }

    private function startDownload():void
    {
    bytesLoaded = 0;
    bytesTotal = 0;
    totalBytesLoaded = 0;

    var url:String = fileInput.text;
    var index:int = url.lastIndexOf(‘/’);
    fileName = url.substring(index+1, url.length);
    file = File.desktopDirectory.resolvePath(fileName);
    status = file.url;

    if(file.exists)
    {
    btn.label = ‘Download';
    mx.controls.Alert.show(‘Please remove “‘+fileName+'” from your disk’, ‘File with the same name already exists’);
    return;
    }
    output.text += ‘Downloading…\n';

    urlStream.load( new URLRequest(url) );
    fData = new ByteArray;
    fileInput.enabled = false;

    fileStream.open(file, file.exists ? FileMode.APPEND:FileMode.WRITE);
    }

    private function pauseDownload():void
    {
    output.text += ‘Downloading is paused\n';
    if(urlStream.connected)
    {
    fData.clear();
    urlStream.readBytes(fData, fData.length);
    urlStream.close();
    fileStream.writeBytes(fData);
    }

    fileStream.close();

    totalBytesLoaded += bytesLoaded;
    trace( “pause size:”+ totalBytesLoaded);

    }

    private function resumeDownload():void
    {
    output.text += ‘Downloading… \n';
    output.text +=’bytes=’+totalBytesLoaded+’-‘+bytesTotal + ‘\n';
    var header0:URLRequestHeader = new URLRequestHeader(‘range’, ‘bytes=’+totalBytesLoaded+’-‘+bytesTotal);
    var request:URLRequest = new URLRequest(fileInput.text);
    request.requestHeaders.push(header0);

    urlStream.load( request );

    fileStream.open(file, file.exists ? FileMode.APPEND:FileMode.WRITE);

    }

    private function onProgress(event:ProgressEvent):void
    {
    bytesLoaded = event.bytesLoaded;
    if(bytesTotal == 0)
    bytesTotal = event.bytesTotal;

    trace( “size:”+ bytesLoaded);

    progressBar.setProgress( (totalBytesLoaded + event.bytesLoaded) / bytesTotal, progressBar.maximum);

    if(urlStream.bytesAvailable == 0) return;
    if(urlStream.connected)
    {
    fData.clear();
    urlStream.readBytes(fData, fData.length);
    fileStream.writeBytes(fData);

    }
    }

    private function onComplete(event:Event):void
    {
    output.text += ‘Download complete\n';
    bytesLoaded = 0;
    bytesTotal = 0;
    totalBytesLoaded = 0;
    progressBar.setProgress(0, 1);

    if(urlStream.connected)
    {
    fData.clear();
    urlStream.readBytes(fData, fData.length);
    urlStream.close();
    fileStream.writeBytes(fData);
    }

    fileInput.enabled = true;
    btn.label = ‘Download';
    fData = null;

    fileStream.close();

    System.gc();
    }

    private function writeFile():void
    {
    output.text += ‘Saving File…\n';
    var fileStream:FileStream = new FileStream;
    fileStream.open(file, file.exists ? FileMode.APPEND:FileMode.WRITE);
    fileStream.writeBytes(fData);
    fileStream.close();
    output.text += ‘File Saved\n';
    }

    private function btnClickHandler():void
    {
    if(bytesLoaded == 0)
    {
    btn.label = ‘Pause';
    startDownload();
    }
    else
    {
    if(urlStream.connected)
    {
    btn.label = ‘Resume';
    pauseDownload();
    }
    else
    {
    btn.label = ‘Pause';
    resumeDownload();
    }
    }
    }

  6. Joel Stobart
    October 10, 2011 at 7:41 am

    Hi,
    Probably a stupid question but, would this work with flash?
    Joel

  7. Mariush T.
    October 10, 2011 at 12:34 pm

    Hi Joel,
    This application wouldn’t work with Flash Player running in the browser. ‘For security reasons, a Macromedia Flash movie playing in a web browser is not allowed to access data that resides outside the exact web domain from which the SWF originated.’
    Best Regards

Leave a comment