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:
- It’s extracted from a zip via FZip.
- Saved to disk via a FileStream.
- Loaded into Flash via an URLLoader.
- Altered as per the change request from my client.
- 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:
- It’s extracted from a zip via FZip.
- Saved to disk via a FileStream.
- Loaded into Flash via an URLLoader.
- Timer started.
- Altered as per the change request from my client.
- Saved back over itself.