File handling

Categories:Framework basics

Contents

xJSFL has rich support for finding, loading and running files:

File and Folder classes

xJSFL finally brings object-oriented File and Folder classes to JSFL. Instead of mucking about with FLfile methods, you can now just create a new File or Folder object and call methods and properties on it.

File and Folder objects are instantiated quite simply like so:

var file = new File('text.txt');

Once you have a reference to the file, you can save, read, move or copy as you would a normal file:

var contents = file.copy('copy.txt').write('I am a copy').contents;

Folders are similar, with the contents property returning an Array of File and Folder instances:

var contents = new Folder('example').contents;
Output.list(contents);
List: Array (depth:1, objects:0, values:2, time:0.0 seconds)
------------------------------------------------------------------------------
array => Array
	 0: "[object File name="text.txt"]"
	 1: "[object File name="copy.txt"]"

For a full breakdown of all File and Folder functionality see the Filesystem section of the API reference.

URI juggling

Traditionally, file loading in JSFL has required file references as an absolute URIs format:

var uri = 'file:///drive|some/path/to/file/with%20spaces%20in%20the%20name.txt';

Whilst this is great for cross-platform development, it's fairly cumbersome for the average developer, and using the native FLfile methods to juggle paths is tedious, error-prone, and difficult to debug.

xJSFL allows you to reference files in URI or path format, converting the latter internally to the absolute URI format Flash understands. It also adds some special xJSFL notation of its own, giving you the following options:

URIs, which are always assumed to be absolute (and are never converted):

'file:///c|/path/to/file.txt'       // absolute URI
'file://///server/path/to/file.txt' // supports network paths (note leading //)

Relative paths:

'file.txt'                          // same folder
'path/to/file.txt'                  // child folder
'../path/to/file.txt'               // parent folder

Absolute paths (Mac users, pay attention to the formats!):

'c:/path/to/file.txt'               // windows
'/path/to/file.txt'                 // mac (default drive)
'/Drive Name/path/to/file.txt'      // mac (named drive)
'Drive Name:path/to/file.txt'       // mac (alternate, windows-like format)

Placeholder variables (see xjsfl.settings.folders) which point to existing named folders:

'{flash}path/to/file.txt'           // {flash}, {swf}, {user}, etc...

xJSFL-root shortcut, which points to your xJSFL installation folder:

'//user/path/to/file.txt'           // leading double-slash

This functionality is handled transparently by the URI class, which is in turn used by all xJSFL's URI-aware functions including:

URI instances

The URI class is a lightweight instantiatable class that represents a single URI.

Instances are created with the new keyword, then can be used or manipulated using the class' API. The resulting instance has various file-related properties and methods that can be accessed directly:

var uri = new URI('some file.txt');
inspect(uri);
Inspect: Unknown (depth:4, objects:0, values:6, time:0.0 seconds)
--------------------------------------------------------------------------------
object => Unknown
	 uri: "file:///E|/Projects/xJSFL/dev/some%20file.txt"
	 folder: "file:///E|/Projects/xJSFL/dev/"
	 name: "some file.txt"
	 extension: "txt"
	 path: "E:/Projects/xJSFL/dev/some file.txt"
	 type: "file"

Most importantly, URI instances cast directly to a URI-formatted string, so they can be passed into any native functions or methods that accept URI-formatted arguments:

var uri = new URI('functions.jsfl');
fl.runScript(uri); // casts to "file:///E|/Projects/xJSFL/dev/functions.txt"

URI static methods

The URI class has nearly 20 static methods for managing and manipulating URIs.

URI.toURI() is the chief method used internally by xJSFL to build URIs, and includes:

  • Full URI juggling as outlined earlier
  • Target paths can be resolved relative to any arbitrary source path
  • Untidy paths or URIs are cleaned up (spaces converted to %20, ../ tokens resolved, backslashes converted to forward slashes, double-slashes removed)

The additional methods fall under the following categories:

File loading

The majority of file loading in xJSFL is handled through xjsfl.file.load() (or its global alias load()) which has the following advantages over using FLfile:

  1. Many different types of path or URI can be passed in (See the section on URI juggling)
  2. Different types of file (settings, libraries, etc) can be found in the framework structure automatically
  3. JSFL files are executed
  4. XML files are returned as actual XML objects
  5. Other files are returned as text
  6. File loads are logged to the main xJSFL log
  7. Load and runtime errors are handled by the framework

The end result is cleaner code and a more flexible way of working with URIs or paths. Here are 5 examples of loading the same file:

Load a relative path:

load('config/snippets.txt');

Load an absolute path:

load('d:/projects/xJSFL/user/config/snippets.xml');

Load an absolute URI:

load(xjsfl.uri + 'user/config/snippets.xml');

Use a placeholder variable:

load('{user}config/snippets.xml');

Automatically find a user-overridden file in the framework structure:

load('snippets', 'config'); // the xml extension is tacked onto "snippets" automatically

Automatic file-finding

Built-into xJSFL is a mechanism that allows user-provided content (such as config and templates) to override system or module-provided content. This allows the user to customise the framework without having to hack any of the core system files.

The way this works in practice is to provide only a filename to a file (rather than an absolute path or URI) then let the framework search for the file in a specific list of locations, returning the first file found.

As a developer, this is mainly done through xjsfl.file.load and xjsfl.file.find methods (although some classes support file finding as standard):

xjsfl.file.load('snippets.xml', 'config');

In this case, xJSFL has a set of rules it follows in order:

  1. It looks first in the user folder:
    1. xJSFL/user/...
  2. If not found, it then looks in each of the installed modules paths:
    1. xJSFL/modules/ModuleA/...
    2. xJSFL/modules/ModuleB/...
    3. xJSFL/modules/ModuleC/...
  3. Finally it looks in the xJSFL core:
    1. xJSFL/core/...

If the file is found, it is loaded and the contents returned if necessary, if not, the method returns undefined.

In practice, the following paths would have been checked:

E:/Projects/xJSFL/user/config/snippets.xml
E:/Projects/xJSFL/modules/Module A/config/snippets.xml
E:/Projects/xJSFL/modules/Module B/config/snippets.xml
E:/Projects/xJSFL/modules/Module C/config/snippets.xml
E:/Projects/xJSFL/core/config/snippets.xml

The purpose of this is to two-fold:

  1. To place the focus on loading files, rather than building URIs
  2. To allow settings files to consecutively override each other in favour of core > modules > user.

Folder manifests

With all this powerful searching capability, xJSFL also provides a way to ignore folders from being included in searches, by way of a manifest.xml file. The concept of manifest files is borrowed from Java, where an extra file in JAR archives is used to define extension and package-related data.

In xJSFL, manifests are currently used for two reasons:

  1. To define common data for xJSFL modules
  2. To define folder-specific directives for xJSFL's file searching

Specifically, the folder section of a manifest file can tell xJSFL to ignore a folder (and its subfolders) from searching, making the process of finding files in the framework quicker.

To ignore a folder from searching (like Snippets asks the framework to ignore the entire assets subtree of 300+ folders) you simply add a file called manifest.xml in a folder, and have it have the following contents:

<manifest>
    <folder>
        <searchable>false</searchable>
    </folder>
</manifest>

Next steps

Comments are closed.