The Stars ...My Destination

adamxx

天下事,法无定法,然后知非法法之
世间人,尤了未了,何妨以不了了之

导航

[转]Apollo的file I/O API

Posted on 2007-04-07 11:03  adamxx  阅读(1152)  评论(1编辑  收藏  举报

Apollofile I/O API


这是翻译的Apollo for Adobe Flex Developer一书第4章Usingthe File System API
原文地址:http://www.nshen.net/blog/article.asp?id=480

简译自某本书的第4章样章,翻译不准确的请指正 :

Apollo的file I/O API允许在用户的电脑上读写文件或文件夹。

file I/O API 包含以下功能:

1 . 创建、删除文件或文件夹
2 . 复制、移动文件或文件夹
3 . 列出文件夹的内容
4 . 取得文件或文件夹的系统信息
5 . 读写二进制文件
6 . 读写文本文件
7 . Serialize and deseialize ActionScript objects

安全模型

Apollo 将提供一个完成的安全模型来管理本地资源,比如文件系统,但在Apollo alpha 1 build这个安全模型还没实现。
访问文件和目录

Apollo applications可以运行在若干平台上,包括Windows 和Mac OS . Apollo file API 使用统一平台的代码语法,所以你不需要为任何特殊的操作系统写代码。

例如,路径在Mac OS和Windows中表现是不同的,

典型的路径在Mac OS上是 /Users/joe/Documents/test.txt

在Windows上是 C:\Documents and Settings\joe\My Documents\test.txt

然而这些你都可以使用相同的Apollo组件,类,方法,属性来访问任意一个操作系统

一个ActionScript的File对象是一个文件或目录的指针

File类有一个静态属性指向用户的文档文件夹,由于不同的操作系统,所以具体的目录也不同


trace(File.documentsDirectory.nativePath)

 // On Windows: C:\Documents and Settings\joe\MyDocuments

// On Mac OS : /Users/joe/Documents

一但一个File object指向了一个目录,你就可以使用resolve()方法修改指向到一个子目录或者文件

例如下边的代码创建一个文件夹在用户文档目录:
var newDir:File=File.documentsDirectory;

newDir=newDir.resolve("ApolloTest");

newDir.createDirectory();

File object 可以指向一个文件或一个目录,即使这个文件或目录并不存在,就像上边的例子一样,我们指向了一个并不存在,但想去创建的一个目录。

常见目录的File Class静态属性

File.appStorageDirectory : 每个Apollo application 都被分配一个唯一的storage目录,这是一个绝好的地方存储一些这个app需要处理的,但用户不需要看到的文件,比如一些log文件,缓存文件,和一些引用的文件

File.appResourceDirectory : application被安装到的目录

File.currentDirectory : 顾名思义不翻译了

File.desktopDirectory : 同上

File.documentsDirectory : 上边讲过,是文档文件夹

File.userDirectory : 这是用户的home directory 例如在Mac OS上是 User/

在Windows上是 c:\\Document and Settings\username

url属性:平台无关的(platform-independent)字符串返回文件或文件夹的位置
例如:
var directory:File = File.userDirectory;
trace(directory.url)
// on Windows: file:///C:/Documents%
// on Mac OS: file:///Users

相反,nativePath属性:返回的是Windows 或是 Mac OS 唯一平台的.

例如:下边代码指定Windows目录下的文件
var file:File = new File( );
file.nativePath = "c:/ApolloTest/surprise.txt";

然而一般情况下更好的方式还是使用上边提到的静态属性(例如File.appStorageDirectory)指向操作系统上已知目录,
然后使用resolve()方法创建一个相对的目录或文件,例如下边的代码
var logFile:File = File.appStorageDirectory;
logFile = logFile.resolve("log.txt");

使用storage目录来存储你的应用程序以后需要访问的文件,但是用户并不需要知道这些。

URI scheme

file:///c:/ApolloTest/test.txt
除了这种常见的URI scheme以外还 支持2种URI scheme

app-storage :指出application的storage目录,就像下边这样
var logFile:File = File.appStorageDirectory;
logFile = logFile.resolve("log.txt");
trace(logFile.url); // app-storage:/log.txt

app-resource :指出application的安装目录,像下边这样
var installDir:File = new File( );
installDir.url = "app-resource:/";
installDir = installDir.resolve("HelloWorld-app.xml");
trace(installDir.url); // app-resource:/HelloWorld-app.xml

不过最常见的还是

file : File对象的url属性返回一个标准的file URI scheme
var file:File = File.documentsDirectory;
file = file.resolve("ApolloTest/test.txt");
trace(file.url);
// On Windows:
// file:///C:/Documents%20and %20Settings/ ... /test.txt
// On Mac OS:
// file:///Users/userName/Documents/ ... /test.txt

方法的同步异步版本:

File类和FileStram类的一些方法,有同步和异步两个版本,比如File.copyFile 和File.copyFileAsync
同步的版本的方法不放弃操作直到file操作完成。异步版本的方法在后台运行,允许ActionScript过程同时发生。
直到异步文件操作完成,一个event被广播给listeners告诉他们操作完成了

这里有一个使用同步copyTo()方法来copy文件的例子
var file1:File = File.documentsDirectory.
resolve("ApolloTest/test.txt");
var file2:File = File.documentsDirectory.
resolve("ApolloTest/copy of test.txt");
file1.copyTo(file2);
trace("Not output until the file is copied.");

这里还有一个使用异步copyToAsync()方法来copy文件的例子
var file1:File = File.documentsDirectory.
resolve("ApolloTest/test.txt");
var file2:File = File.documentsDirectory.
resolve("ApolloTest/copy of test.txt");
file1.copyToAsync(file2);
file1.addEventListener(Event.COMPLETE, completeHandler);
trace("This line executes before the complete event.");
trace("So does this line.");
private function completeHandler(event:Event):void {
trace("Done.");
}

下边列出File类的异步方法(所有的异步方法都一个同步方法的副本)

方法 事件
copyToAsync( ) complete, ioError
deleteDirectoryAsync( ) complete, ioError
deleteFileAsync( ) complete, ioError
listDirectoryAsync( ) directoryListing, ioError
moveToAsync( ) complete, ioError
moveToTrashAsync( ) complete, ioError

当你打开一个文件,无论用FileStream对象的open()还是openAsync()方法,首先都是同步打开文件操作,然后异步打开操作。更多的信息请看这章后边的“The open( ) and openAsync( ) Methods”

当你需要在文件操作期间使用ActionScropt程序的时候(比如进度条动画)你可以使用异步版本的方法。

例如当你写一个小的文件(1兆或更小)你可以使用FileStream对象的open() (同步版本的方法)方法,但当你写的文件比较大

或不知道文件大小的时候你可以使用异步方法openAsync();

想了解更多异步方法,请看Programming ActionScript 3.0 的“Handling Events”那章

你可以在这里找到他: http://livedocs.macromedia.com/flex/2/docs/Part5_ProgAS.html

读目录的内容

File.listDirectory()方法返回指定目录的文件或文件夹的File object数组

例如下边的代码列出桌面文件夹的内容:
var directory:File = File.desktopDirectory;
var contents:Array = directory.listDirectory( );
for (var i:uint = 0; i < contents.length; i++) {
if (contents[i].isDirectory) {
trace(contents[i].name);
} else {
trace(contents[i].name,
contents[i].size,
"bytes");
}
}

它只会列出指定文件夹根目录的文件和文件夹,不会递归查找子文件夹。你当然也可以写代码来遍历子文件夹
但如果你真这么做了,也许最好使用File.listDirectoryAsync()方法,这样在列表的同时可以做些显示进度条之类的事了

更多请看第5章的"Getting a Directory Listing"


取得文件信息

File类包含了许多关于文件或目录的属性

属性 描述

exists 状态,这个文件或文件夹是否存在,这是个非常用有用的检查,例如,在你试图读或写或移动删除某个文件之前检查一下 是否存在


isDirectory 状态,判断这个File object是否是一个文件夹(true)还是一个文件(false)。你将在试图使用文件夹专有操作之前(例 如listDirectory()方法)检查一下这个file object是不是一个文件夹

isHidden 状态,这个文件或文件夹是否隐藏

nativePath Notes,这个文件或文件夹操作系统特有的路径(system-specific path )


parent Notes,这个File实例的父目录

url Notes,该文件或文件夹操作系统无关的路径(system-independent path).

File类还从FileReference类继承了一些有用的属性

属性 描述

creationDate 文件或文件夹的创建日期

modificationDate 文件或文件夹最后修改的日期

name 文件或文件夹的名字

size 文件大小以 bytes为单位.

复制、移动文件与文件夹

File.copyTo()和File.moveTo()方法复制或移动一个文件或文件夹到指定的新位置。例如 下边的代码复制用户文档目录子目录

Apollo Test文件夹下的test.txt 到application storage目录下的UserData子目录:
var file1:File = File.documentsDirectory.resolve("Apollo
Test/test.txt");
var destination:File = File.appStorageDirectory.
resolve("User Data");
destination.createDirectory( );
var file2:File = destination.resolve("test.txt");
file1.copyTo(file2);

注意,调用File.createDirectory()方法是为了确保目标文件夹存在。

如果复制或移动操作将要很长时间,你可能需要调用File.copyToAsync()和File.moveToAsync()方法

所有的这些方法都包含一个clobber参数,你可以把这个参数设置为true来允许overwrite现有的文件,这个参数默认是false的

创建文件和文件夹

File类的File.createTempFile()和File.createTempDirectory()静态方法允许你创建一个临时的文件或文件夹。Apollo确保这个临时文件或文件夹是新的唯一的。例如下边代码创建一个临时文件:
var bufferStorage:File = File.createTempFile( );

当你关闭一个apollo application时候,临时文件和文件夹不会自动删除,所以你一般时候需要在关闭application之前删除临时文件夹。更多信息看下一节删除文件和文件夹

File.createDirectory()方法允许你在File object指定的位置上创建一个目录
var directory = File.documentsDirectory;
directory = directory.resolve("ApolloTest");

当你打开一个可写的FileStream object时,目录自动被创建。更多内容下面

删除文件和文件夹

File.deleteFile()方法永久删除一个文件,File.deleteDirectory()方法永久删除一个文件夹。

File.moveToTransh()方法允许你移动文件或文件夹到系统的垃圾回收站

所有的这些方法也有一个异步的副本

读写文件

FileStream类提供方法来读写文件

这里是读写文件的一般过程:

1 . 建立一个File object指向这个你要读写的文件。 不会的到上边找

2 . 建立一个FileStream对象 例如

var stream:FileStream= new FileStream();

3. 调用FileStream.open()或FileStream.openAsync()方法,传递file object参数和一个fileMode参数,例如

stream.open(file,FileMode.READ)

FileMode的相关信息"文件打开模式"章节会讲到

4. 如果你调用FileStream.openAsync()方法,那么建立一个适当的监听函数。详细下边章节会讲到

5.对你的数据调用适当的读写方法。 详细下边的“读和写方法”会讲

6.关闭文件,使用FileStream.close()方法。例如: stream.close()

3,4,5步后边会详细讲,这里是一个同步读utf-8文本文件的例子
var file:File = File.appStorageDirectory;
file = file.resolve("settings.xml");
var stream:FileStream = new FileStream( );
stream.open(file, FileMode.READ);
var data:String = stream.readUTFBytes(stream.
bytesAvailable);
stream.close( );

还有一个异步读同样数据的例子
var file:File = File.appStorageDirectory;
file = file.resolve("settings.xml");
var stream:FileStream = new FileStream( );
stream.openAsync(file, FileMode.READ);
stream.addEventListener(Event.COMPLETE, readData);
var data:String;
private function readData(event:Event):void {
data = stream.readUTFBytes(stream.bytesAvailable);
stream.close( );
}

open()和openAsync()方法

在你读或写文件之前你需要先打开这个文件
当你用FileStream.openAsync()方法打开文件的时候,这个打开是异步的,你需要注册个事件监听者来监视这个过程。
FileStream.open()方法以同步的方式打开文件,如果你的application打开文件使用同步方法,所有后续的读写操作会同步进行
下边的例子中stream.open(),stream.writeUTFBytes(), 和 stream.close()将在下次调用之前全部完成。
var newFile:File = File.documentsDirectory;
file = file.resolve("ApolloTest/test.txt");
68 | Chapter 4: Using the File System API
var stream:FileStream = new FileStream( )
stream.open(file, FileMode.WRITE);
stream.writeUTFBytes("This is some sample text.");
stream.close( );

这种同步操作好处在于只写较少的代码就能完成任务,坏处就是如果操作时间很长那么后续的As代码会被延时执行。所以,如果你
操作一个较大的文件,或者打开文件在较慢的网络上共享,你应该考虑使用FileStream.openAsync()方法

当你使用openAsync()方法时,下边的所有过程全部为异步的:

文件关闭(Closing the file)

当文件关闭时 FileStream object广播一个close事件

读数据到缓存(Reading data into the read buffer)

当数据被读时FileStream object广播 progress事件,然后当所有数据读完时候广播一个complete事件,一旦数据被读完后,调用一个读方法(例如 readBytes())读数据就是同步过程了

I/O 错误

FileStream object在遇到错误时候广播一个 ioError 的事件。有很多原因会出现这种情况 例如
尝试去打开一个不存在的文件或尝试写一个已经locked的文件。然而一些错误比如尝试去读的文件还没有open,将会抛出异常(而不 会广播 ioError事件)因为Apollo runtime能立刻察觉到错。

在你调用FileStream.openAsync()方法之前,你的application需要建立一些事件监听函数来处理这些他们感兴趣的事件。

下边的例子使用异步读模式打开一个文件。当这个文件被打开后,complete事件将被广播出去(除非有错误的时候会广播ioError事件)
然后completeHandler()处理函数中调用FileStream.readBytes()方法,这将开始读取文件为一个bytesArray,在异步模式,当所有的bytes都被读完后,complete事件将被广播出去:
var file:File = File.documentsDirectory.resolve("ApolloTest/test.txt");
var stream:FileStream = new FileStream( );
stream.addEventListener(ProgressEvent.PROGRESS,progressHandler);
stream.addEventListener(Event.COMPLETE, completeHandler);
stream.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
stream.addEventListener(Event.CLOSE, closeHandler);
stream.openAsync(file, FileMode.READ);
var data:ByteArray = new ByteArray( );
private function progressHandler(event:ProgressEvent):void {
trace(stream.bytesAvailable, "bytes read.");
}
private function completeHandler(event: Event):void {
data = stream.readBytes(stream.bytesAvailable);
stream.close( );
}
private function ioErrorHandler(event:IOErrorEvent):void {
trace("An I/O error was encountered.");
}
private function closeHandler(event: Event):void {
trace("File closed.");
}

文件打开模式

FileStream.open( ) 方法和 FileStream.openAsync( )方法都需要两个参数:需要打开的文件,和fileMode参数,fileMode参数是一个定义FileStream object对象能力的字符串。fileMode参数可能的值都被定义在FileMode类的衡量中了

例如,下边的代码同步打开一个文件写操作,不能读
stream.open(file, FileMode.WRITE);

这里是FileMode类的衡量以及他们的意思

FileMode.APPEND 只写模式,所有被写的数据都会附加到文件的最后 Upon opening, any nonexistent file is created.

FileMode.READ 只读模式,file必须存在 (missing files are not created).

FileMode.UPDATE 读写模式,数据可以写在文件的任何位置或者附加到尾部。Upon opening, any nonexistent file is created.

FileMode.WRITE 只写模式,如果文件不存在,将会创建新的文件,如果存在将会被覆盖

读和写方法

FileStream类包含一堆读和写的方法,每个和数据被读写的格式对应。例如,你可以使用readUTFBytes()和WriteUTFBytes ()方法读写一个bytes Array,也可以readByte()和writeByte()方法一次读写一个byte,总而言之有25个读和写的方法。详细的信息要看Apollo Alpha 1发布的ActionScript 3.0 Language Reference。

读写文本数据也许看起来价值不高,你可以在文件中编码文本readUTFBytes()和writeUTFBytes()方法提供读写UTF-8格式的文本。
readMultiByte( ) 和writeMultiByte( )方法允许你为文件指定不同的字符编码。

Thereare other factors to consider as well. For example, a UTF file
may start with a UTF byte order mark (BOM) character,
which defines the UTF encoding and the byte order (or
“endianness”) of the data.

更多信息, 看 Apollo Developer’s Guide (http://www.adobe.com/go/apollodocs).的“Data formats, and choosing the read and write methods to use” 章节

More Information
For examples of reading and writing files, see the following
sections in Chapter 5:
• “Writing a Text File from a String”
• “Reading a Text File into a String”
• “Encoding Bitmap Data into PNG or JPEG Format and
Writing It to the File System”
• “Serializing and De-Serializing ActionScript Objects to
the File System”