Just another flash platform blog 

Responding to write operations using the FileStream object

January 2nd, 2008 Posted in Adobe AIR

Recently I’ve been playing alot with Adobe AIR trying to get myself up to speed with all the major features, so when I come up with an idea for something I’ll usually try and write it in AIR.

Shortly after my son was born last November I began writing a slide show app in Flex to show the snaps of the little guy to close family (thats still not completely written but I’ve learned alot about using URLStreams!). Anyway I quickly realised that the super high-res images that my camara produces are going to fill my hosting space very quickly not to mention take ages for my parents to download. What I needed was to be able to quickly batch process images at the same downscale percentage and the same quality. Now Im sure this is quite possible to do using actions in Photoshop, but then Im not a designer so what better than to re-invent the wheel and write my own app using AIR, right? :)

So thats what I have done – well almost still crossing the T’s and dotting the I’s. I’ll release it here once I have it at a reasonable state of completeness.

Anyway, getting back to the point of the post: What I decided should happen is that once you have references to all the files that are to be processed it should follow the steps below for each image:

  1. Stream in the image data.
  2. Convert to a Bitmap.
  3. Parse the BitmapData with JPEGEncoder.
  4. Write the resulting ByteArray to a FileStream object.
  5. When the write is complete go back to step 1 until all images are processed.

Pretty simple stuff. However since FileStream read operations dispatch Event.COMPLETE events when reading is finished I made the assumption that the write operations would do the same thing. This isnt the case, FileStream write operations do not dispatch COMPLETE events. So whats left for detecting the end of write operation? Well there are a couple of possibilities depending on whether you are writing syncronously or asynchronously (read the docs if you dont know what this is ;) ). If you are writing synchronously then the whole of the data is written before any more code is executed so  you can simply close the FileStream in the lines following the write and listen to the close event e.g.:


public function write () : void
{
var myFile:File=File.documentsDirectory.resolvePath("test.txt");
var myFileStream:FileStream = new FileStream();
myFileStream.addEventListener(Event.CLOSE, closeHandler);
myFileStream.open(myFile, FileMode.WRITE);
myFileStream.writeUTFBytes("hello world");
myFileStream.close();
trace("started.");
}

public function closeHandler(event:Event):void 
{
       trace("finished.");
}

Now thats fine for many situations, but in this case it wasnt for me as I wanted to monitor write progress as I might be dealing with some quite large files, so the file for writing must be asynchronous writing so the progress events can be written. The problem with this is that the rest of the code in the example above would continue while the writing is happening including the close, which would probably end up with the event being dispatched prematurely and worse not all of the file being written.

public function write () : void
{
var myFile:File=File.documentsDirectory.resolvePath("test.txt");
var myFileStream:FileStream = new FileStream();
myFileStream.addEventListener(Event.CLOSE, closeHandler);
myFileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, progressHandler);
myFileStream.openAsync(myFile, FileMode.WRITE);
myFileStream.writeUTFBytes("hello world");
trace("started.");
}

public function progressHandler(event:OutputProgressEvent):void
{
if (event.bytesPending==0) event.target.close();
}

public function closeHandler(event:Event):void
{
trace("finished.");
}

So here we’re still waiting for the stream to dispatch a close event before continuing, but we’re only closing the stream once we are sure that all the bytes have been written.

  • Share/Save/Bookmark
  1. 4 Responses to “Responding to write operations using the FileStream object”

  2. By Steve Carpenter on Nov 5, 2008

    Meant to post this a while ago – thanks, great example and got me and others out of a fix!

  3. By Javier on Dec 18, 2008

    I’ve been looking for this and so far the
    OutputProgressEvent was the only solution.

    But then I find that in AIR 1.5 (don’t know about previous versions) you can call the close method right after calling the write method.

    The docs says that the filestream object will wait until the last byte is written to execute the close action (and dispatch the CLOSE event).

    Something like this:

    var fileStream:FileStream = new FileStream();
    fileStream.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);

    try {
    fileStream.openAsync(file, FileMode.WRITE);
    fileStream.writeObject(settings);
    fileStream.close();

    } catch(e:IOError) {
    trace(”Save IOError ” + e.message);
    fileStream.close();

    } catch(e:Error) {
    trace(”Save Error ” + e.message);
    fileStream.close();
    };

    Check this link:
    http://help.adobe.com/en_US/AIR/1.5/devappsflash/WS5b3ccc516d4fbf351e63e3d118666ade46-7db1.html

  4. By mattjpoole on Dec 18, 2008

    Hi Javier,

    The example was built against AIR 1.0, however calling close straight away is only meant for synchronous OS calls and not asynchronous.

    In a synchronous call the fileStream.writeObject(settings) line would complete before moving onto the next line where you close it. Thats fine if you happy for your program to wait while the write operation takes place.

    For most situations eg writing largish files its much better to use the approach I outlined above.

  1. 1 Trackback(s)

  2. Mar 9, 2008: Socks, Dregs and Bacon Roll » Blog Archive » ProgressJPEGEncoder

Post a Comment