Read and write files from local filesystem with OpenLaszlo by using ActionScript3

Today i will try to read and write local files from a local storage. After a few searches with google, i found several similar samples. Now i integrate these with the sample from www.mikechambers.com within my OpenLaszlo code. For both, reading and writing files, we need the usual main structure, with a runtime switch and passthrough for the actionscript libraries.

Click here for a quick demo 😉

At first, we have look at the reading of a file. For that we create a few small functions, some of them act as an event handler.
 
1. The function that invokes the loading. Here we instantiate a FileReference object, register the required eventlistener and open the browser window for selecting a file. Further you will find here the fileFilterValue variable, within you are able to restrict the allowed file types for selecting.

<!---	called when the user clicks the load file button -->
<method name="loadFile" returns="void">
<![CDATA[	
	
	// create the FileReference instance
	this.fr = new FileReference();

	// listen for when they select a file
	this.fr.addEventListener(Event.SELECT, this.onFileSelect);

	// listen for when then cancel out of the browse dialog
	this.fr.addEventListener(Event.CANCEL, this.onCancel);

	// open a native browse dialog that filters for text files
	this.fr.browse([new FileFilter(this.fileFilterValue, this.fileFilterValue)]);
								
]]>
</method>

 
2. The function that is called, when the user has selected a file. Here we register two further eventlistener, the onLoadError and onLoadComplete eventlistener, and starting the loading progress.

<!---	called when the user selects a file this.from the browse dialog -->
<method name="onFileSelect" args="e:Event" returns="void">
<![CDATA[
	Debug.write(this, "->onFileSelect()");

	// listen for when the file has loaded
	this.fr.addEventListener(Event.COMPLETE, this.onLoadComplete);

	// listen for any errors reading the file
	this.fr.addEventListener(IOErrorEvent.IO_ERROR, this.onLoadError);

	// load the content of the file
	this.fr.load();						
]]>
</method>

 
3. The onLoadComplete function is called, when the file is transferred to the flash application. Here we receive the file contents and clean up the FileReference instance.

<!---	called when the file has completed loading -->
<method name="onLoadComplete" args="e:Event" returns="void">
<![CDATA[
	Debug.write(this, "->onLoadComplete()");

	// get the data this.from the file as a ByteArray
	var data:ByteArray = this.fr.data;

	// Get the file content
	this.setAttribute("fileContent", data.readUTFBytes(data.bytesAvailable));
	
	// clean up the FileReference instance	
	this.fr = null;					
]]>
</method>

 
4. The onLoadError function will be called in case of a transfer-error.

<!---	called if an error occurs while loading the file -->
<method name="onLoadError" args="e:IOErrorEvent" returns="void">
<![CDATA[
	Debug.error(this, "->onLoadError(): " + e.text);					
]]>
</method>

 
5. The onCancel function is used of both, the reading and writing action, and is just called when the user aborts the file selecting browser window or file saving browser window.

<!---	called if the user cancels out of the file save dialog -->
<method name="onCancel" args="e:Event">
<![CDATA[
	Debug.write(this, "->onCancel()");
	this.fr = null;						
]]>
</method>

 
For the writing of files you need just the three following functions, some of that are also act as a event handler.

1. The saveFile function invokes the saving action. Here we instantiate again a FileReference object, register the requiered eventlistener and open the browser window for selecting the destination for the file.

<!---	called when the user clicks the save file button -->
<method name="saveFile" args="fileContent ='', fileName ='test.txt'" returns="void">
<![CDATA[	
	
	// create the FileReference instance
	this.fr = new FileReference();

	// listen for the file has been saved
	this.fr.addEventListener(Event.COMPLETE, this.onFileSave);

	// listen for when then cancel out of the save dialog
	this.fr.addEventListener(Event.CANCEL, this.onCancel);

	// listen for any errors that occur while writing the file
	this.fr.addEventListener(IOErrorEvent.IO_ERROR, this.onSaveError);

	// open a native save file dialog, using the default file name
	this.fr.save(fileContent, fileName);
								
]]>
</method>

 
2. The onSaveError function will be called in case of an error while saving.

<!---	called if an error occurs while saving the file -->
<method name="onSaveError" args="e:IOErrorEvent">
<![CDATA[
	Debug.write(this, "->onSaveError(): ", e.text);
	this.fr = null;								
]]>
</method>				

 
3. The onFileSave function will be called when the file is successfully saved.

<!---	called once the file has been saved -->
<method name="onFileSave" args="e:Event">
<![CDATA[
	Debug.write(this, "->onFileSave()");
	this.fr = null;							
]]>
</method>

 
All these functions are capsuled in a class, that is extends the node object.

<class name="readAndWriteFileReference" extends="node">

	<passthrough>
		import flash.net.FileReference;
		import flash.net.FileFilter;
		import flash.events.IOErrorEvent;
		import flash.events.Event;
		import flash.utils.ByteArray;
	</passthrough>

	<!---	FileReference -->
	<attribute name="fr" type="expression" />

	...

Is this class implemented, you will only need to create an instance of that and bind an eventlistener with it. Now you are able to load and write file contents, just by calling the load and save function. A canvas could look like:

<canvas name="readAndWriteFileReference" width="800" height="550">
	
	<include href="./readAndWriteFileReference.lzx" />
		
	<attribute name="columnWidth" type="number" value="400"/>
	<attribute name="textHeight" type="number" value="${canvas.height-canvas.buttonBar.height}"/>
	
	<readAndWriteFileReference name="readAndWriteFile">
		<handler name="onfileContent">
		<![CDATA[				
			canvas.textView.textLoad.setAttribute("text", this.fileContent);
		]]>
		</handler>				
	</readAndWriteFileReference>		
		
	<simplelayout axis="y" spacing="0" />
	<view name="textView" width="$once{canvas.columnWidth*2}" height="$once{canvas.textHeight}">
		<simplelayout axis="x" spacing="0" />
		<edittext name="textSave" width="$once{canvas.columnWidth}" height="$once{canvas.textHeight}" multiline="true" />
		<edittext name="textLoad" width="$once{canvas.columnWidth}" height="$once{canvas.textHeight}" multiline="true" />
	</view>
				
	<view name="buttonBar" layout="axis: x; spacing:0" height="27">
		<button text="Save file" onclick="canvas.readAndWriteFile.saveFile(canvas.textView.textSave.text, 'test.txt');" width="$once{canvas.columnWidth}" />
		<button text="Load file" onclick="canvas.readAndWriteFile.loadFile();" width="$once{canvas.columnWidth}" />		
	</view>	
				
</canvas>

And now, happy loading and saving 😉

Click here for a quick demo 😉

Sourcecode: OpenLaszlo - ReadAndWriteFileReference.zip (1101)

If you found some bugs or have some Tips, please contact me.

    • Ankush Khurana
    • June 17th, 2012

    Hello,

    I am new to openLaszlo and i want to create a file at run time on client side and want to give a File Download pop up from the browser to client. Can you please help me out ?
    I want to know how should i create a file at run time on client side?
    Is it possible to create a file without saving it on server side ?

    Thanks in advance.

      • tdeuling
      • June 17th, 2012

      Hi,
      you can write a file client-side in the way i wrote here.
      But, the user must select a location where the file should be saved. You’re not able to save the file automatically in background. For such action you may need to write you application with Adobe AIR, and not with Adobe Flash – but with OpenLaszlo you can also create Adobe AIR applications 😉 I wrote about it too, and Raju Bitter gives in the past also some examples with AIR.
      I hope i could help you 😉

    • deva
    • June 30th, 2012

    Nice and useful … Thanks.

  1. No trackbacks yet.