Mike Chambers

code = joy

Reading and Writing Local Files in Flash Player 10

with 39 comments

One of the new features in Flash Player 10 are new ActionScript FileReference APIs that allow Flash content to directly read and write data to the user’s system.

Prior to Flash Player 10, in order to read or write a file to the user’s system, Flash content would first have to bounce it off of a server, and then load it back to the users system before it could be accessed. This was not only a hassle to program, but added additional application latency and resource usage.

The new functionality is achieved through the addition of two new APIs on the FileReference class:

FileReference.load() : Loads data from a file selected by the user.
FileReference.save() : Saves data to a file location selected by the user.

A couple of points to keep in mind:

  • The load() and save() APIs can only be called in response to user interaction (such as a button click).
  • The locations of the loaded and save files are not exposed to ActionScript.
  • The APIs are asynchronous (non-blocking).

Below are two examples that show how to use the APIs. The examples use Flex for the UI, but the ActionScript is the same regardless of whether you are using Flex or not. The examples are fully commented.

Read a file from the users system:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

	<mx:Script>
		<![CDATA[
			import flash.net.FileReference;
			import flash.net.FileFilter;
			
			import flash.events.IOErrorEvent;
			import flash.events.Event;
			
			import flash.utils.ByteArray;
		
			//FileReference Class well will use to load data
			private var fr:FileReference;
			
			//File types which we want the user to open
			private static const FILE_TYPES:Array = [new FileFilter("Text File", "*.txt;*.text")];
		
			//called when the user clicks the load file button
			private function onLoadFileClick():void
			{
				//create the FileReference instance
				fr = new FileReference();
				
				//listen for when they select a file
				fr.addEventListener(Event.SELECT, onFileSelect);
				
				//listen for when then cancel out of the browse dialog
				fr.addEventListener(Event.CANCEL,onCancel);
				
				//open a native browse dialog that filters for text files
				fr.browse(FILE_TYPES);
			}
			
			/************ Browse Event Handlers **************/
			
			//called when the user selects a file from the browse dialog
			private function onFileSelect(e:Event):void
			{
				//listen for when the file has loaded
				fr.addEventListener(Event.COMPLETE, onLoadComplete);
				
				//listen for any errors reading the file
				fr.addEventListener(IOErrorEvent.IO_ERROR, onLoadError);
				
				//load the content of the file
				fr.load();
			}
			
			//called when the user cancels out of the browser dialog
			private function onCancel(e:Event):void
			{
				trace("File Browse Canceled");
				fr = null;
			}
			
			/************ Select Event Handlers **************/
			
			//called when the file has completed loading
			private function onLoadComplete(e:Event):void
			{
				//get the data from the file as a ByteArray
				var data:ByteArray = fr.data;
				
				//read the bytes of the file as a string and put it in the
				//textarea
				outputField.text = data.readUTFBytes(data.bytesAvailable);
				
				//clean up the FileReference instance
				
				fr = null;
			}
			
			//called if an error occurs while loading the file contents
			private function onLoadError(e:IOErrorEvent):void
			{
				trace("Error loading file : " + e.text);
			}
			
		]]>
	</mx:Script>


	<mx:Button label="Load Text File" right="10" bottom="10" click="onLoadFileClick()"/>
	<mx:TextArea right="10" left="10" top="10" bottom="40" id="outputField"/>
	
</mx:Application>

Write a file to the users system:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

	<mx:Script>
		<![CDATA[
			
			import flash.net.FileReference;
			
			import flash.events.IOErrorEvent;
			import flash.events.Event;
		
			private static const DEFAULT_FILE_NAME:String = "example.txt";
		
			//FileReference Class well will use to save data
			private var fr:FileReference;
						
			
			/********** UI Event Handlers **************/
			
			//called when the users types in the textarea
			//note valueCommit should be used, but is broken in the flex build 
			//I am using
			private function onInputChange():void
			{
				//enable button if there is any text to save
				saveButton.enabled = (inputField.text.length > 0);
			}
			
			//called when the user clicks the load file button
			private function onSaveClick():void
			{
				//create the FileReference instance
				fr = new FileReference();
				
				//listen for the file has been saved
				fr.addEventListener(Event.COMPLETE, onFileSave);
				
				//listen for when then cancel out of the save dialog
				fr.addEventListener(Event.CANCEL,onCancel);
				
				//listen for any errors that occur while writing the file
				fr.addEventListener(IOErrorEvent.IO_ERROR, onSaveError);
				
				//open a native save file dialog, using the default file name
				fr.save(inputField.text, DEFAULT_FILE_NAME);
			}
			
			/***** File Save Event Handlers ******/
			
			//called once the file has been saved
			private function onFileSave(e:Event):void
			{
				trace("File Saved");
				fr = null;
			}
			
			//called if the user cancels out of the file save dialog
			private function onCancel(e:Event):void
			{
				trace("File save select canceled.");
				fr = null;
			}
			
			//called if an error occurs while saving the file
			private function onSaveError(e:IOErrorEvent):void
			{
				trace("Error Saving File : " + e.text);
				fr = null;
			}
		]]>
	</mx:Script>


	<mx:Button label="Save File" right="10" bottom="10" id="saveButton" 
											click="onSaveClick()" enabled="false"/>
	<mx:TextArea right="10" left="10" top="36" bottom="40" id="inputField" 
									editable="true" change="onInputChange()"/>
	<mx:Label text="Enter text to save" left="10" top="10" fontWeight="bold"/>
	
</mx:Application>

In addition to the events shown in the examples above, the following events are also broadcast by the APIS:

ProgressEvent.PROGRESS
: Gives progress on the reading or writing of the file
Event.OPEN : Broadcast when the file is opened for reading or writing.

While it will also be possible to use these APIs in Adobe AIR, in general, you will want to use the AIR File APIs as they provide more functionality and flexibility.

You can download the Flash Player 10 ActionScript APIs docs from here.

You can find more information on Flash Player 10 on labs.

Written by mikechambers

August 20th, 2008 at 10:52 am

Posted in General

39 Responses to 'Reading and Writing Local Files in Flash Player 10'

Subscribe to comments with RSS or TrackBack to 'Reading and Writing Local Files in Flash Player 10'.

  1. What’s the thinking behind the limitation to .load() and .save() in that they can only be called in ‘response to user interaction’?

    Alex MacCaw

    20 Aug 08 at 11:04 am

  2. @Alex MacCaw

    So you dont visit a website, and Flash content starts randomly reading and writing your files without your knowledge or permission.

    mike chambers

    mesh@adobe.com

    mikechambers

    20 Aug 08 at 11:40 am

  3. Mike,
    But surely a dialog would pop up for the user to select a file – they could just click cancel. Also I could potentially make a SWF that looked exactly like a textbox, for example, that would trick the user into clicking it. I’m not sure the limitation solves the problem.

    Alex MacCaw

    20 Aug 08 at 11:44 am

  4. Unfortunately, this will break a ton of sites out there. You cannot call File.Browse() through ExternalInterface anymore. We rely on that at AOL for our photo uploader and I know that Flickr, Picnik and many other sites do this.

    The ability to tie javascript and Flash so tightly together (as pushed in Flash 9 and AIR) is a huge reason that I use Flash in almost all my projects. I typically do UI in HTML and javascript, but use Flash underneath for uploading, media playback, byte manipulation, etc.

    If Flash 10 releases like this, it will instantly break a ton of very popular sites (AOL, Yahoo) as well as make a lot of developers re-think about using Flash, as we now have to expose it in the UI which is not always possible. Please reconsider this security feature.

    Dan kantor

    20 Aug 08 at 1:09 pm

  5. @Dan Kantor


    Unfortunately, this will break a ton of sites out there.

    This API is new to Flash Player 10, so it wont break anything (as nothing is using it yet).

    I think what you are referring to are changes to security policy that affect existing FileReference APIs. You can find more information on that, as well as leave comments on this post:

    http://theflashblog.com/?p=423

    mike chambers

    mesh@adobe.com

    mikechambers

    20 Aug 08 at 1:18 pm

  6. Alex –
    I also think one of the issues mentioned elsewhere was that without the user interaction, the origin of the Browse window is unknown. If you had 3 SWFs on a page (think mySpace or Facebook) , and a browse window popped up, the user wouldn’t know which one spawned it and may inadvertently compromise their system.

    john

    21 Aug 08 at 3:58 pm

  7. John,
    Just to be Devil’s Advocate for a second, I could create a transparent swf and overlay it over another – tricking a user into compromising their system. Another argument proposed is that an attacker could repeatedly open up the file browser, eventually forcing a user into selecting a file – I guess there’s some truth to this – but is there any examples of attackers actually using this technique? I know there’s always a compromise between security and convenience – but surely this is going too far? The Flash team strive really hard to make Flash backwards compatible, but aren’t they shooting themselves in the foot here? Sorry for the rant – but I’m really not convinced this measure is justified.

    Alex MacCaw

    22 Aug 08 at 3:36 am

  8. [...] can read more about this on Mike Chambers blog, there are also sample applications to [...]

  9. Hi Mike,
    Great work, but how about selecting an mp3 file and playing that back?
    I managed to load a text file, and an image, code like loadedImage.source = imageFR.data;, where loadedImage si mx:Image and imageFR is FileReference is working, but how to pass the content of a loaded mp3 file to the Sound component?
    Also, I would like to select a video file and play that back without uploading to a server and downloading from there.

    Kun Janos

    29 Oct 08 at 1:08 am

  10. This seems like a hackers dream come true.

    Dude

    2 Nov 08 at 11:15 pm

  11. I for one am very pleased about this future, yes its a potential security hole if not looked after correctly but then you could quite easily say that about any other web development platform api, javascript, applets, activeX, silverlight and many others are far more evil than flash even ‘with’ these new features.

    Thanks to adobe, I can now develop web apps that do what the client has asked for without sending it all back to the server first. Case in point saving images of a chart plus CSV data to local disk. And I have needed this functionality in the last three apps I wrote so I’m quite happy with it and will be ingorning the scaremongers.

    L :0

    SpookuLuke

    4 Nov 08 at 8:14 am

  12. When loading the ByteArray from the data property of a FileReference object, is there any way to buffer the bytes so they don’t all get read into memory?

    We would like to use the fact that we have access to the ByteArray to be able to perform a resumable upload using Flash by sending the file one chunk at a time, however, for large files this becomes a problem if the whole file gets read into memory.

    Are there any workarounds?

    Jesse

    6 Nov 08 at 6:46 am

  13. I tried this as is in Flex Builder 3 .. and it doesnt work.. it doesnt even compile because it references to some API that dont exist.

    Marc

    12 Nov 08 at 7:12 pm


  14. I tried this as is in Flex Builder 3 .. and it doesnt work.. it doesnt even compile because it references to some API that dont exist.

    Have you setup Flex Builder 3 to compile to Flash Player 10?

    mike chambers

    mesh@adobe.com

    mikechambers

    13 Nov 08 at 12:16 am

  15. Sometimes it’s not so much security as it is lazy programming. URLRequest can be used to load a file locally.

    Knight Chat X

    13 Nov 08 at 1:27 am

  16. Use string and data manipulation functions to read the data as you would old school it works just fine assuming you know how to use the basic editing functions.

    Knight Chat X

    13 Nov 08 at 1:39 am

  17. i installed the 3.2.0.3794 SDK .. and it still doesnt work

    Marc

    13 Nov 08 at 7:30 am

  18. the only way i got this to work was with Flash CS4 and nothing else

    Marc

    13 Nov 08 at 7:32 am

  19. Ok got it to work in Flex… just need to do alot of modifications to the project (like change the swc, then changing the way it compiles and then changing the version needed for the player)

    Marc

    13 Nov 08 at 7:39 am

  20. ok .. forget it .. it just messes up the project.. so it works once .. then when you reopen the project.. flex cries about some stuff being invalid

    Marc

    13 Nov 08 at 7:42 am

  21. ok … sorry last post i swear…

    i have to tell flex compiler to juste require flash 10 and thats it.. it seems… got a guide that messed up the other test.. but now it works… thank you the code is great by the way

    Marc

    13 Nov 08 at 7:46 am

  22. [...] can read more about this on Mike Chambers blog, there are also sample applications to [...]

  23. [...] Files are a lot easier to work with in player 10 than I though they would be. Writing to a text file is as simple as fr.save(someString, someName) loading is also a lot less painful than I thought it might be. Mike Chambers has written a good getting started guide here. [...]

  24. [...] can read more about this on Mike Chambers blog, there are also sample applications to [...]

  25. Being able to read and save files from Flash sounds great. I am a game programmer in Flash, but not being able to save files was strongly limiting the type of games I created (for example, creating an RPG was unthinkable until now). I know there are still the shared objects, but these files are hard to get by the average user, so transferring from computer to computer is a pain, and integratign with other apps, a wizard’s work. Not to mention that plenty of people keep erasing their cookies, etc. So I’m happy to know that reading and saving files will be possible / is possible from Flash.

    If security is a concern, then I propose a few approaches:

    - Files can only be saved in specific folders. Maybe a preset folder in the C: drive in windows, for instance. Maybe C:\flashdata This way everyone knows where it is, but can’t save elsewhere and do bad things, same for Linux and Mac OS. Saving in directories within that one would be ok. This way, no one can leak any file into a dangerous directory (such as the OS folder / directory)

    - Limit the file extension to something predefined. Maybe .fd (flash data), so no one will try to save a .exe or anything of the sort (have flash simply not allow it), so if someone tries to pull a malicious executable, it simply will not launch.

    It is only a matter of thinking a bit. Having the capability of writing and reading files from Flash is a great thing, and we should not give our backs to this possibility. By using some common sense, it can still be used safely and not be hacker-friendly.

    Some other readers posted concerns that this would require flash to be visible. I think this could be addressed by only requiring it to be visible IF there will be any file saving or reading, and never otherwise.

    Hope someone involved in the development of Flash Player 10, 11, etc. gets to read this. ;-)

    SomeNick

    11 Feb 09 at 1:04 pm

  26. Mike,
    Is is possible to locate a users home directory from a Flash standalone application when the application is not in the users directory? Or is a wrapper application(Zinc, mProjector, etc.) still the only way to achieve this? I’m hoping to avoid the wrapper if possible.

    I would like to read/create a prefs file located somewhere in the users directory, I.E. Application Support.

    John I.

    12 Mar 09 at 9:35 am

  27. Is it possible to call the save() command from a loaded swf? We have a preloader swf that loads in a main swf. When we do this the save() function fails from the main swf. If we remove the preloader and just start with the main file, We can save. Any workaround for this?

    scott

    1 Jul 09 at 4:12 pm

  28. hi..
    load() is until 100MB.
    Can you convert big size file to ByteArray ???
    not Air.

    YoungJae

    25 Aug 09 at 5:44 pm

  29. Hey…
    I get the FileRefrence API, but have no save() method. Havent checked if pointing to Flash 10.

    Francois

    14 Oct 09 at 6:58 am

  30. got it working, was using Flash 9.

    thx for the great article

    Francois

    14 Oct 09 at 7:15 am

  31. Hi Mike,

    Tried to compile the 2 MXML you have given in Flex 3.

    The first one produced 2 Compilation Errors.

    fr.load();
    &
    var data:ByteArray = fr.data;

    The Second one showed 1 comiplation Error

    fr.save(inputField.text, DEFAULT_FILE_NAME);

    I’m stumped. Can you check ‘em and revert back?

    Cheers mate.

    Sid

    1 Nov 09 at 3:30 am

  32. Hey Mike,

    I understand the Compilation error of your MXML is due to the fact that my Flex 3 is NOT setup for FP10.

    I work in Flex. My question is – if I set it up for FP10, will my new apps in Flex 3 still run in FP9 as well. If it doesn’t, it could spell disaster for me. Please advise.

    Cheers mate.

    Sid

    1 Nov 09 at 3:54 am

  33. Thank you soooooooooo much for sharing :)

    Suma Gowda

    24 Dec 09 at 9:46 pm

  34. would you be kind enough to show me how to pass those values from a bytearray to a datagrid?…

    miguel

    3 Jan 10 at 9:24 pm

  35. Hi

    I have need to have the IE Favorites automatically imported by reading directly from the local file system

    in AIR application. How its Possible ?

    Thanks
    Bambam

    Bambam Choudhary

    21 Apr 10 at 1:28 pm

  36. In Air the fileReference objects in fileReferenceList do not fire the complete event when doing fileList[i].load(). In Flex it works fine. Adobe has not taken bug reports on this appropriately.

    Greg

    11 Oct 10 at 7:49 pm

  37. [...] code was required. It’s even less complicated than reading/writing local files in Flash (see Mike Chambers’ post on [...]

Leave a Reply

Follow

Get every new post on this blog delivered to your Inbox.

Join other followers: