Adobe's new Integrated Runtime (AIR) will be released at some point this year (a beta is currently available here). The release of AIR will bring new possibilities in how applications communicate with client machines. Previous to the Adobe Integrated Runtime, Flash applications adhered to a security model that drastically handicapped what your applications could and couldn't do. For more information on the general Flash player security model see this page; for more info on Flash player security and Flex 2.01 see this page. With AIR, all of the following are now possible:
The ability to:
- create files and directories
- list the contents of directories
- copy and move files and directories
- read and write text and binary files
- serialize and deserialize ActionScript objects and classes to the file system
- get system information on files and directories
In this blog post I'll talk about what new classes are available in Flex 3 (Flex "Moxie" M2 SDK to be specific) that make all this possible. In my next post I'll show an example of how to use the file system API in a real-world application.
A new package is included in Flex 3 called flash.filesystem and it includes the following classes: File, FileMode, and FileStream. Let's take a closer look at each of these new classes.
flash.filesystem.File
The file class is a representation of a file or directory on the file system. It's also used to represent a file or directory that you wish to create. Included in the File class are properties and methods for getting information about the file system and for performing operations on the file system like creating or deleting files and directories. Coupling the File class with the FileStream class (which we'll examine in a minute) you can read and write binary and text files on the client machine.
The first important aspect of the File class is how it abstracts file system paths for you making it easier to write applications. If you remember, AIR is a cross-platform runtime available on Windows, Macintosh and - in the future - Linux. These operating systems represent file and directory paths in totally different ways. For example, my home directory on Windows might be C:\Documents and Settings\aaron\ while on a Mac it would be /Users/aaron/. The File class has several static properties that represent operation system agnostic paths.
File.appStorageDirectory
Every AIR application is given a storage directory. This is a great place to store preference files, cache files, log files, or any other file specific to the application running on the client. Example application storage directories are /Users/aaron/Library/Preferences/[AIR_application_ID]/Local Store/ for Mac and C:\Documents and Settings\aaron\Application Data\[AIR_application_ID]\Local Store\ for Windows where [AIR_application_ID] is the unique ID of your application. As an example, the application ID for my twitterAIR app is com.trajiklyhip.twitterAIR. This ID is set by the developer in the AIR application descriptor file.
File.appResourceDirectory
This is the directory where an AIR application is installed. For instance /Users/aaron/Applications/ on Mac and C:\Documents and Settings\aaron\Local Settings\Application Data\[AIR_application_name]\ for Windows.
File.userDirectory
The base directory for the user. Example: /Users/aaron/ on Mac and C:\Documents and Settings\aaron\ on Windows. This directory serves as the base directory for all subsequent directories described below.
File.desktopDirectory
The users desktop directory. Example: /Users/aaron/Desktop/ on Mac and C:\Documents and Settings\aaron\Desktop\ on Windows.
File.documentsDirectory
The users documents directory Example: /Users/aaron/Documents on Mac and C:\Documents and Settings\aaron\My Documents\ on Windows.
File.currentDirectory
This is the directory where the AIR application was launched. Note, users can move applications from their initial location to other locations on the file system. Thus, the value of this static property may differ from the value stored in File.appResourceDirectory.
In order to make use of these static properties you must first create an instance of the File class. For example, to create an instance of the File class that points to the users documents directory you would write the following code:
var docsDirectory:File = File.documentsDirectory;
Once you have an instance of the File class created there are several properties of the instance that describe the file or directory the instance references. These include:
File.isDirectory
Whether the instance refers to a directory (true) or a file (false). Checking the value of this property is useful before calling any directory specific functions like File.listDirectory(), which returns the list of files and directories stored in the File instance.
File.isHidden
Whether the instance refers to a hidden directory or file on the file system.
File.exists
A boolean value indicating whether the resource exists. You should check this value before attempting to write or read a specified file or directory.
File.nativePath
This property reveals the operating system specific path to a file or directory. From the example code above (File.documentsDirectory) this value might be /Users/aaron/Documents on Mac and C:\Documents and Settings\aaron\My Documents\ on Windows.
File.url
This property is the reverse of File.nativePath and reveals the operating system independent path to a file or directory preceded by a URL scheme. From the example code above this value might be file:///Users/aaron/Documents on Mac and file://C:/Documents%20and%20Settings/aaron/My Documents/ on Windows.
File.parent
The parent directory (as an instance of File) of the File instance.
Other useful properties of a File instance include: File.creationDate, File.modificationDate, File.name, File.size, File.type, File.creator, and File.extension. Note, some of these are only valid for instances of the File class that point to files.
Returning to the previous example, what if you wanted to trace the value of the user's documents directory? You can't just write trace(docsDirectory) as docsDirectory is a File instance, and not a string. Using the properties described above, you could write the following:
var docsDirectory:File = File.documentsDirectory;
trace(docsDirectory.url);
// file:///Users/aaron/Documents
If you wanted to create a reference to an actual file in the user's documents directory and determine whether it exists or not you would write:
var myFile:File = File.documentsDirectory.resolve("MyFile.txt");
trace(myFile.exists);
// true or false depending on whether the file exists or not
flash.filesystem.FileMode
The second class I want to discuss today is the FileMode class. This class relates to various modes with which a file can be opened. In ColdFusion, this type of low-level access is mostly hidden. In fact, you don't even have to explicitly open and close files in order to work with them. In AIR, you must perform these steps. When it comes time to open a file you'll need to decide how you wish to open the file based on what you are going to be doing with it. Here are your options - which are constant values (hence the upper case) of the FileMode class. You use these constants in conjunction with the FileStream class (covered below) when opening files.
FileMode.READ
The file is opened in read-only mode and must already exist in the given location. An File I/O exception will be thrown if you attempt to open a non-existing file in FileMode.READ mode.
FileMode.WRITE
The file is opened in write-only mode. If the file does not exist in the given location it will be created. If the file does exist, it will be completely overwritten.
FileMode.UPDATE
The file is opened in read/write mode. Data can be written to any position in the file or appended to the end. If the file does not exist it will be created automatically.
FileMode.APPEND
The file is opened in write-only mode and data is automatically written to the end of the file. If the file does not exist it will be created automatically.
flash.filesystem.FileStream
The FileStream class is used to read and write files. It's where all the real heavy-lifting is done in terms of opening connections to files, writing to those files, and closing the files. Included in the class are some 26 methods for reading and writing text files, binary files, or ActionScript objects to files. The type of read/write method you choose will determine how data is encoded in files as well as whether the reading/writing actions are performed synchronously or asychronously.
For example, the FileStream.readUTFBytes() and FileStream.writeUTFBytes() methods read and write UTF-8 encoded text respectively. If you want to specify a different character encoded, the Filestream.readMultiByte() and FileStream.writeMultiByte() methods are available. These last two methods take two arguments, the second of which is the character encoding you want to use. Here are two examples of writing UTF-8 encoded data into a file. The first does so synchronously and the second asynchronously. Which method you choose should be based on your application strategy but a good rule is write large files - that may take a long time to write - asynchronously. This will allow your application to continue functioning without waiting on the file to write to the file system.
Write UTF-8 encoded string data to a file on the user's desktop synchronously.
// Create a reference to MyFile.txt on the user's desktop.
var myFile:File = File.desktopDirectory.resolve("MyFile.txt");
// Create a new FileStream instance.
var fs:FileStream = new FileStream();
// Create a String we'll use to write inside the file.
var myString:String = "Here's a string of text.";
// Open MyFile.txt in write-only synchronous mode.
fs.open(myFile, FileMode.WRITE);
// Write the string to the file synchronously.
fs.writeUTFBytes(myString);
// Close the file.
fs.close();
Write UTF-8 encoded string data to a file on the user's desktop asynchronously.
import flash.events.Event;
// Create a reference to MyFile.txt on the user's desktop.
var myFile:File = File.desktopDirectory.resolve("MyFile.txt");
// Create a new FileStream instance.
var fs:FileStream = new FileStream();
// Add the function fileWrittenComplete as a close listener to the file stream.
fs.addEventListener(Event.CLOSE, fileWrittenComplete);
// Create a String we'll use to write inside the file.
var myString:String = "Here's a string of text.";
// Open MyFile.txt in write-only asynchronous mode.
fs.openAsync(myFile, FileMode.WRITE);
// Write the string to the file asynchronously.
fs.writeUTFBytes(myString);
// Close the file.
fs.close();
// Event handler for when the file has been written.
public function fileWrittenComplete(event:Event):void {
trace("MyFile.txt has been written to the file system.");
}
In addition to writing textual data to the file system, the FileStream class allows you to write binary data (such as a JPEG) or a full ActionScript class or generic Object to the file system. The overall File API included in Flex 3 is relatively easy to work with and extremely powerful. Using it properly opens your desktop applications to a whole new realm of possibilities. Stay tuned in the near future to read more about real-world ways to utilize these new classes in your applications.














(text below taken from the downloads page for Flex Builder 3 Beta)
Flex Builder 3 Beta - Eclipse Plugin
This download provides the Flex Builder 3 beta as an Eclipse plugin that can be used on either Macintosh or Windows platforms. The prerelease version of the Flex 3 SDK is included with this prerelease Flex Builder 3 download. Eclipse version 3.2.1 or higher is required in order to install and use this version of Flex Builder 3 beta.
Lastly, in looking at my final example above (asynchronously writing a file) there may be an issue with the fs.close(); method call. Since the file stream is opened asynchronously the close() method may be getting called out of turn. It would be best to move the fs.close() into the fileWrittenComplete function (assuming all we wanted to do was write to the file and nothing else). If we were going to perform several write actions on the file, the fs.close() method could be strategically placed somewhere else.
Well, I just put your code right away inside the <mx:Script> tag without adding anything. The errors, saying something about undefined property, show up when I save the file. Now, I try putting the code inside a function and have it called when a button is clicked. The errors are gone and a file is created successfully on my desktop.