Using ByteArray to Serialize AS3 Classes for AIR, Web and Everywhere!

by troy on November 3, 2007

When using AIR's FileStream to write AS3 classes to ByteArray, I've found that the same file format works for loading in via URLLoader, as well as what's uploaded using FTP. This isn't surprising, but wanted to test anyway.

What this means is that ByteArray is a groovy ubiquitous format for storing full classes and dependencies and references, via ByteArray.writeObject and ByteArray.readObject (provided registerClass is used), without nececessarily having to parse them manually though that is still suggested for versioning and class evolution. Meaning you can create a file using AIR , send that file to a friend in email, and have them open it up in a flash based webpage, and they operating in a webpage could Http POST the change back to you. The ByteArray can have rich complexity, classes, self references, collections, etc. This could be used to save whole game states (even massive multiplayer, NPC brains, etc). Or in my target case debugging outside other non-AIR runtimes to speed development.

How to save to the same directory the swf AIR is running from

This took me a bit to figure out. Primarily as I'm using AIR to write the files in Flash CS3 and it's not immediately apparent in the docs, how to target the 'self' directory of the swf. This isn't recommended in the docs (which I agree) but in the case I'm using it for it makes sense to do so. The API for AIR is here

                // this is in url path 
		var file:File = File.applicationDirectory.resolvePath( "example.jpg" );
		trace("file " + file.url + " " +file.nativePath ); //outputs app:/example.jpg, and "C:\SomeDirectory\Somepath\example.jpg"
		var wr:File = new File(file.nativePath);
		// Create a stream and open the file for asynchronous reading
		var stream:FileStream = new FileStream(); wr, FileMode.WRITE );

This would be swf._url in AS2, or in AS3 DisplayObject.loaderInfo.url , as when using relative links in URLLoader to load whatever you're saving this will resolve properly in AIR. Turns out flash.filesystem.File.applicationDirectory is the droid you are looking for. It's not fully qualified (e.g. file:C:\somedirectory...) when traced it looks like:


unless you use the file.nativePath which is required in order to actually write to the directory. So you can use still this in old school string name parsing the swf name out, so you don't have to use File.applicationResourceDirectory if your looking to make a single swf for both AIR and Web use, and on the web, the AIR libraries won't be accessible.

Here's two handy scripts to help inspect ByteArray's, the first looks at the 1's an 0's, the other looks at the objects in the stream, using the getQualifiedClassName, and if it finds an Array or sub ByteArray attempts to inspect it.
/* converts byteArray to binary like

0 = 110
1 = 1011
2 = 1001000
3 = 1100101

function traceBits(bA:ByteArray) {
	for (var i:int = 0; i < bA.length; i++) {
		bA.position = i;
		var inte:uint = bA.readByte();
		trace(i+ " = " + inte.toString(2));
function traceByteArray(bA:ByteArray) {
	var o;
	var cnt:int = 0;
	var cnm:String;
	var o2;
	var cnt2:int = 0;
	var cnm2:String;
	try {
		while (true) {
			o = bA.readObject();
			cnm = getQualifiedClassName(o);
			trace( cnt++ + " " + o + " : " + cnm);
			if (cnm == "flash.utils::ByteArray") {
				try {
					cnt2 = 0;
					cnm2 = "";
					while (true) {
						o2 = o.readObject();
						trace(" " +  cnt2++ + " " + o2 + " : " + getQualifiedClassName(o2));
				} catch (err:Error) {
			} else if (cnm == "Array") {
				trace("array contents...");
				try {
					var ar:Array = o as Array;
					trace("ar " + ar);
				} catch (err:Error) {
	} catch (err:Error) {