Before the release of Flash 10 we needed to use some sort of a server side proxy or Javascript in order to read or write file in the user’s system. We would send the request to a proxy, which will handle the request and send it back to Flash once completed.
Flash Player 10 has exposed two new methods in FileReference: load and save.
The new methods allow you to read and write data right into the user’s local system. You get information about the files such as modify date, creator, size and other properties, however unlike AIR’s FileStream API the location of the files will not be visible to us and we can only do asynchronous calls.
Asynchronous operations perform operations in the background without waiting for the operation to complete, long processes such as uploading or downloading a large file will not impact the application and the user can keep using the application. Synchronous operations on the other hand, the operation is waiting for the original operation to complete before allowing the user to do any interactions with the application.
Recently, Adobe have closed a gap and forced the load and save methods to be used follow user interaction, such as clicking a button, so the user will be aware of being asked to save or load and not see a browse window comes out of nowhere.
The process of reading and writing files is easy, however I created a helper to make the process of reading and writing files even easier. The class called: LocalFileHelper.as and it uses the FileReference API.
Let’s take a look at the code that shows a simple implementation of loading and saving a file:
<FxApplication xmlns="http://ns.adobe.com/mxml/2009"
minWidth="1024"
minHeight="768" initialize="initializeHandler(event)">
<Script>
<![CDATA[
import com.elad.framework.utils.events.LocalFileErrorEvent;
import com.elad.framework.utils.events.LocalFileLoadedEvent;
import mx.controls.Alert;
import com.elad.framework.utils.events.LocalFileEvent;
import com.elad.framework.utils.enum.FileTypeFormat;
import com.elad.framework.utils.LocalFileHelper;
import mx.events.FlexEvent;
private var localFileHelper:LocalFileHelper;
protected function initializeHandler(event:FlexEvent):void
{
localFileHelper = new LocalFileHelper( FileTypeFormat.FILE_FILTER_TEXT_TYPE );
localFileHelper.addEventListener(LocalFileEvent.FILE_LOAD_BROWSE, onFileSelect);
localFileHelper.addEventListener(LocalFileEvent.FILE_SAVE_BROWSE, function():void { trace("Save browse complete"); } );
localFileHelper.addEventListener(LocalFileEvent.FILE_SAVE_SUCCESSFULLY, function():void { trace("Save complete!"); } );
localFileHelper.addEventListener(LocalFileEvent.FILE_CANCEL, function():void { Alert.show("Cancel"); } );
localFileHelper.addEventListener(LocalFileErrorEvent.FILE_ERROR, function():void { trace("file error") } );
}
private function loadFile():void
{
localFileHelper.browse();
}
private function onFileSelect(event:LocalFileEvent):void
{
localFileHelper.addEventListener(LocalFileLoadedEvent.DATA_LOADED, onDataLoaded );
localFileHelper.load();
}
private function onDataLoaded(event:LocalFileLoadedEvent):void
{
output.text = LocalFileHelper.convertByteArrayToText( event.byteLoaded );
}
private function saveFile():void
{
localFileHelper.save( output.text, "test.txt" );
}
]]>
</Script>
<FxButton label="Load" click="loadFile()" />
<FxButton label="Save" click="saveFile()" x="84"/>
<TextArea id="output" y="37" width="397" height="327"/>
</FxApplication>
Take a look at the utility class:
package com.elad.framework.utils
{
import com.elad.framework.utils.enum.FileTypeFormat;
import com.elad.framework.utils.enum.InteractionStates;
import com.elad.framework.utils.events.LocalFileErrorEvent;
import com.elad.framework.utils.events.LocalFileEvent;
import com.elad.framework.utils.events.LocalFileLoadedEvent;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.net.FileReference;
import flash.utils.ByteArray;
public class LocalFileHelper extends EventDispatcher
{
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
/**
* @private
*
*/
private var fileType:Array;
/**
* @private
*
*/
private var fileReference:FileReference;
/**
* @private
*
*/
private var interactionState:String;
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Default constructor, which call the <code>reset</code> method to set the file reference and type.
*
* @param fileType you can set the type of files you want to use. The file types are listed in <code>FileTypeFormat</code>
* @see com.elad.framework.utils.enum.FileTypeFormat
*
*/
public function LocalFileHelper(fileType:Array=null)
{
reset(fileType);
}
/**
* Reset method will allow the implementation to reset the file reference and set again the file type filter.
* The default file type is <code>FileTypeFormat.FILE_FILTER_ALL_FILES_TYPE</code> which will allow selecting
* any file type.
*
* @param fileType you can set the type of files you want to use. The file types are listed in <code>FileTypeFormat</code>
* @see com.elad.framework.utils.enum.FileTypeFormat
*
*/
public function reset(fileType:Array=null):void
{
if (fileType == null)
{
fileType = FileTypeFormat.FILE_FILTER_ALL_FILES_TYPE;
}
this.fileType = fileType;
fileReference = new FileReference();
}
/**
* The browse method is useful when you need to load a file, you first browse for the file and than you load the file.
* When you browse for the file the file type that was selected is used.
*
*/
public function browse():void
{
this.interactionState = InteractionStates.BROWSE;
fileReference.addEventListener(Event.SELECT, onFileSelectEventHandler);
fileReference.addEventListener(Event.CANCEL, onFileCancelEventHandler);
fileReference.browse(fileType);
}
/**
* Static method to convert the <code>ByteArray</code> data into a string.
*
* @example
* <listing version="3.0">
* var text:String = LocalFileHelper.convertByteArrayToText( event.byteLoaded );
* </listing>
*
* @param data
* @return
*
*/
public static function convertByteArrayToText(data:ByteArray):String
{
var retVal:String;
retVal = data.readUTFBytes(data.bytesAvailable);
return retVal;
}
/**
* Method to load a file. The method add event listeners and use the <code>fileReference.load</code>
* method to do the loading. To load a file you must first call the <code>browse</code> method.
*
*/
public function load():void
{
if (this.interactionState != InteractionStates.BROWSE)
{
this.dispatchEvent( new LocalFileErrorEvent( "You must browse before trying to load a file!" ) );
}
this.interactionState = InteractionStates.LOAD_FILE;
fileReference.addEventListener(Event.COMPLETE, onCompleteEventHandler);
fileReference.addEventListener(IOErrorEvent.IO_ERROR, onIOErrorEventHandler);
fileReference.load();
}
/**
* Save method can be used to save data into a file. The method must follow a user interaction.
*
* @param data Any type of data
* @param fileName You can set the file name, ie: "test.txt"
*
*/
public function save(data:*, fileName:String):void
{
this.interactionState = InteractionStates.SAVE_FILE;
fileReference.addEventListener(Event.COMPLETE, onCompleteEventHandler);
fileReference.addEventListener(IOErrorEvent.IO_ERROR, onIOErrorEventHandler);
fileReference.addEventListener(Event.SELECT, onFileSelectEventHandler);
fileReference.addEventListener(Event.CANCEL, onFileCancelEventHandler);
fileReference.save(data, fileName);
}
//--------------------------------------------------------------------------
//
// Event handlers
//
//--------------------------------------------------------------------------
/**
* Method to handle the two cases where the browse gets calls:
*
* <ul>
* <li>Once you browse to load a file</li>
* <li>Once browse is used when saving a file</li>
* </ul>
*
* <p>The internal <code>InteractionStates</code> is used to know which case we are dealing with.
*
* @param event
*
*/
private function onFileSelectEventHandler(event:Event):void
{
fileReference.removeEventListener(Event.SELECT, onFileSelectEventHandler);
fileReference.removeEventListener(Event.CANCEL, onFileCancelEventHandler);
if (this.interactionState == InteractionStates.BROWSE)
this.dispatchEvent( new LocalFileEvent( LocalFileEvent.FILE_LOAD_BROWSE ) );
else
this.dispatchEvent( new LocalFileEvent( LocalFileEvent.FILE_SAVE_BROWSE ) );
}
/**
* Method to be called in case the used decide to cancel the option to save or load a file.
* The method is related to the browse window.
*
* @param event
*
*/
private function onFileCancelEventHandler(event:Event):void
{
fileReference.removeEventListener(Event.SELECT, onFileSelectEventHandler);
fileReference.removeEventListener(Event.CANCEL, onFileCancelEventHandler);
this.dispatchEvent( new LocalFileEvent( LocalFileEvent.FILE_CANCEL ) );
}
/**
* In case an IOError gets called when trying to load or save a file this method will
* be dispatched.
*
* @param event
*
*/
private function onIOErrorEventHandler(event:Event):void
{
fileReference.removeEventListener(Event.COMPLETE, onCompleteEventHandler);
fileReference.removeEventListener(IOErrorEvent.IO_ERROR, onIOErrorEventHandler);
this.dispatchEvent( new LocalFileErrorEvent( "FileReference: IOErrorEvent.IO_ERROR received: "+event.toString() ) );
}
/**
* Method to handle the two cases where the complete gets calls:
*
* <ul>
* <li>Once complete loading a file</li>
* <li>Once coomplete saving a file</li>
* </ul>
*
* <p>The internal <code>InteractionStates</code> is used to know which case we are dealing with.
*
* @param event
*
*/
private function onCompleteEventHandler(event:Event):void
{
fileReference.removeEventListener(Event.COMPLETE, onCompleteEventHandler);
fileReference.removeEventListener(IOErrorEvent.IO_ERROR, onIOErrorEventHandler);
if (this.interactionState == InteractionStates.LOAD_FILE)
this.dispatchEvent( new LocalFileLoadedEvent( fileReference.data ) );
else
this.dispatchEvent( new LocalFileEvent( LocalFileEvent.FILE_SAVE_SUCCESSFULLY ) );
}
}
}
Example:
- To load a file: select the load button, which will prompt you to select a text file.
- To save a file: type in the box and select the save button. You will be prompt to browse and select a place to save the file under.






















