ActionScript 3 – Error #3013: File or directory is in use.

Hit a snag with an Air project I’m working on tonight. Got right to the end of the last set of requested changes and then started getting the error: Error #3013: File or directory is in use. It occurs with both new files and old files I’m replacing. Took me a while to suss it out but I now have a fix that works a treat.

The last task on my change list was to allow renaming of some info within an XML file. That XML file goes through a number of stages:

  1. It’s extracted from a zip via FZip.
  2. Saved to disk via a FileStream.
  3. Loaded into Flash via an URLLoader.
  4. Altered as per the change request from my client.
  5. Saved back over itself.

The problem seems to happen because the FileStream in step 2 isn’t closing fast enough. I only use the URLLoader’ed data after its Event.COMPLETE has been called. Here’s a snippet to show how I’m using the FileStream in step 2:

var stream:FileStream = new FileStream();
stream.open(temp_file, FileMode.WRITE);
stream.writeBytes(zipped_file.content);
stream.close();

The zipped_file variable is a FZipFile that represents a file retrieved from the zip file. After that snippet I load the XML file using an URLLoader and carry on with the rest of the steps. The error occurs when I hit the last step indicating that it hasn’t been closed yet. As you can clearly see in the above snippet, I am calling close(). I’m doing the file writing synchronously which means I don’t seem able to listen for the Event.CLOSE or Event.COMPLETE events. They never get called.

I did a bit of googling around and saw several other people with this problem. Some of them are using it asynchronously and report that the CLOSE event is getting called successfully prior to them trying to re-save the file. This led me to not bother trying to rewrite my code to work asynchronously as the snippet is only a small chunk of what I’m doing.

Anyhow. My simple fix is to implement a delay between closing the first stream and saving the second. This is achieved using a Timer like so:

var timer:Timer = new Timer(100, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, this.timedSave);
timer.start();

Just a tiny delay seems to do it, bit of a pain having to do this, feels like a proper naughty hack, but I’ve been working on this change list for about 12 hours straight and I just want the nightmare to end! I moved the final two stages inside the “timedSave” function so they only happen after the timer has completed. The revised process is:

  1. It’s extracted from a zip via FZip.
  2. Saved to disk via a FileStream.
  3. Loaded into Flash via an URLLoader.
  4. Timer started.
  5. Altered as per the change request from my client.
  6. Saved back over itself.
Comments: 8

Leave a reply

Your email address will not be published. Required fields are marked *

  • Romuald
    Romuald

    Hey there,
    I got the exact same problem, did you find anything beside the timer?
    Romu

  • Anonymous
    Anonymous

    I figured it was probably just a bug in Air. I started this project using an older version of Air. There have been a number of updates since then and Air 2.0 is just around the corner. I’m supposed to do an update to the project I had the problem with in a few months so I’ll look into this again at that time. I read that they changed the Air 2.0 install process so I can use my own installer which means I should be able to drop the whole FZip part of the process. I’ll probably just use NSIS which is what I use for all my other non Air based projects. Sorry, I know that isn’t the answer you were hoping for.

  • Amir
    Amir

    This error was making me mad!! as I had reviewed my code a thousand times and found no mistake and my project was an event based complex one and yes including fzip library. At leas now I know what`s caused it. And by the way the problem is still there in air 2 beta2
    Thank you David

  • jleigh
    jleigh

    Give this a try, seems to be working for me.

    // where you are complete with file add event listener and call cancel. deleteFile.addEventListener(Event.CANCEL, onDeleteFile);
    deleteFile.cancel();

    public function onDeleteFile(e:FileEvent):void
    {
    e.file.deleteFile();
    }

  • ix
    ix

    Why do you suggest people creating memory leaks?! Indeed there is safer function to use timed call to a function: setTimeout().

  • Anonymous
    Anonymous

    ah, jleigh, that is a great snippet, thank you for that. If I find myself working in this area again I’ll be sure to do it that way instead. So much more elegant.

    ix, nothing mentioned so far has had anything to do with memory leaks. Can you see something we are missing? setTimeout is just a static way of using a Timer instance which is what I did in my first post.

  • Andy
    Andy

    Thanks, that 100ms delay did the trick. Spent like 4 hours trying to fix it… how annoying!

  • Red Bull John
    Red Bull John

    excellent. thanks for the tidbit. for gc() concerns maybe use timer.addEventListener(TimerEvent.TIMER_COMPLETE, this.timedSave,false,0,true);

I am the writing on the wall, the whisper in the classroom! Without these things, I am nothing. So now, I must shed innocent blood. COME WITH ME!

— Candyman