在Director中保存用户数据 在多媒体产品的开发过程中，我们常常会遇到需要将用户的一些进度、在文本字段中的项目、对环境所作的某些改变（如窗口或精灵的位置的移动）等进行保存的情况。 如果只是将数据存储到列表中，当然在应用程序运行时，可以随时从列表中获得信息，然而一旦用户退出应用程序后，这些信息便永久地消失了。要想保存这些信息以便下一次运行时能够继续使用它们，必须要永久性地存储数据。这里给大家介绍两种永久性地存储数据的方式，既可以在Director电影的内部字段中存储这些永久性数据，也可以将它们写入到Director电影外部的独立的文件中。
在字段中存储数据
你可以创建只用于存储数据的字段而不将它们显示到舞台上，在电影播放过程中利用“Lingo”的“SaveMovie”命令将这些字段同电影一同保存起来。请记住，一定要使用“SaveMovie”命令将电影保存，否则，字段在你退出电影时将回到它原来的状态，任何在电影播放中输入的数据都会丢失。如果数据量非常小，你可以直接存取字段。如果数据较多，你可以把字段内容读取到列表中，然后使用列表来访问数据，这样会运行得更快一些，当你要退出电影时，将这些数据再存储回字段中。
例如，在一个多媒体游戏中，你需要存储关于用户参数选择的一些数据，如用户上一次退出时的位置和时间。在下面的Lingo程序中你将在退出电影前创建一个字段来存储用户数据，这个字段名为“USER”：
on stopMovie
global CurrentLocation
global UserScore
put CurrentLocation into item 1 of line 1 of field "USER"
put UserScore into item 2 of line 1 of field "USER"
saveMovie --保存电影，千万可别忘记了
end
如果是多用户的程序，可能会有多个人使用你的程序，并且每个人都会存储各自的信息，这时，你必须判断不同的用户，并取出相应的信息。在这种情况下，你可以使用属性列表，将每个人的名称存储为一个属性，然后对这个属性使用“sort”命令进行排序，这样用户信息便按用户名来索引。你可以方便地直接检索到想要的项目。下面是一个包含了相同信息的属性列表“UsersInfo”。
[
"Wuhong":[#CurrentLocation:"Sea war scene1",#UserScore:560]
"Zhouyan":[# CurrentLocation:"Sea war",#UserScore:330]
"Linling":[#CurrentLocation:"Palace",#UserScore:770]
"John":[#CurrentLocation:"Land",#UserScore:1930]
]
要为该列表添加新的项，可以使用以下Lingo程序：
on addUser UserName,Location,Score
global UsersInfo
set Sublist=[:]
--设定属性中的子列表
setaProp Sublist,# CurrentLocation, Location
--将用户的当前位置存入到子列表中
setaProp Sublist,# UserScore, Score
--将用户的得分存入到子列表中
setaProp(UserInfo,Username,Sublilst)
--将子列表添加到属性列表中
end
当你要从列表中获取用户信息时，你可以参照使用如下的Lingo程序：
on getUserScore UserName
global UserInfo
getProp(getProp(UserInfo,UserName),UserScore)
end
在这里，我们还要强调一下，列表只能作为临时存储，在电影结束前，你必须将列表数据存储到一个字段中，并使用“SaveMovie”命令来保存它。不过你不必将列表一项一项地存入到字段中，你可以一次将整个列表都写入到字段中。Director会先将该列表转换成为一个字符串，然后再将它写入到字段中。如下的Lingo语句将列表UserInfo写入到字段“DataBackup”中：
put UserInfo into field "DataBackup"
当电影重新启动时，你可以使用如下的Lingo程序将这些数据从字段中转入到一个列表中。
on loadList
global UserInfo
put value(field"DataBackup") into UserInfo
sort(UserInfo)
end
函数value用来将存储在字段中的字符串转换回列表。你应该对这个列表排序，以便能够快速查找。这是因为在将列表存储为字段时，丢失了它的内部索引。注意，在一个字段中最多可以保存约为32KB的文本。所以，列表在转换后必须小于32KB。否则，列表的多余部分将不能存储到字段中而会丢失。
千万要注意的是，如果你的多媒体电影在最后运行时是存储在某些不可写入的介质上的话，这种方法是行不通的。
使用外部文件来存储数据
当要保存的数据相当大的时候，使用字段或列表来保存这些数据便有了许多缺点，首先由于字段或列表都要先读取到内存中，这将增加电影的内存需求，同时，它还会增加电影的文件大小。另外，这也使得其它人不能对数据项作出修改。
要存储大量的数据，将它存储为外部文件。这样，能够保持Director电影的文件大小并减小对内存的需求。因为你可以从文件中一次只取出一条记录来获取数据。
利用Director本身所具有的FileIO Xtra你可以读取或写入到ASCII文件。选择“Modify/Movie/Xtras”命令打开“Movie Xtras”对话框，单击“Add”按钮并选择“FildI-O.X32”，再单击“OK”按钮便可以打开FileIO Xtra。FileIO处理是模态的，如果你按Read模式打开一个文件，那么你必须先将它关闭然后按Write方式重新打开才能写入。Write模式将删除文件中所有的已有内容。你也可以采用ReadWrite模式打开文件，这样你既可以读，也可以写。你还可以使用SetPosition方法在文件的特定位置上进行写入，使用GetLength可将指针移动到当前的末尾。你可以通过使用mNew命令创建一个FileIO Xtra的新实例，并把它赋给某个变量来打开一个文件。在下面的Lingo程序中打开一个已经存在的文件，并写入新数据到其中。字符串末尾的RETURN字符用来表示该记录的结束：
on appendMode oneRecord
--oneRecord是一个字符串它看起来应该像这种方式
--“Garden Hose,XRP2132,32.99”
global catalogItems
if objectP(catalogItems) then catalogItems(mDispose)
--如果这个文件已经打开，那么将它关闭
set catalogItems=new(xtra "fileio")
openFile(catalogItems,"cat.txt",2)
--如果“cat.txt”文件没有同调用的电影文件放置在同一个文件夹中
--则在这里应该包含它完整的路径。而最后一个参数2则是告诉FileIO
--如何来打开这个文件，0代表Read/Write，1代表Read，2代表Write
setPosition(catalogItems,getLength(catalogItems))
--将写入的位置设定为打开文件的结尾处
-- getLength将返回打开文件的长度（字符数）
WriteString(catalogItems,oneRecord&RETURN)
-- RETURN（回车符）用来在文件中分行
--如果你想要对文件使用ReadLine或者你需要在一个文本编辑器中阅读这个文件，你应该以RETURN符来分隔各行
put integer(field"Record Count")+1 into field" Record Count"
closeFile(CatalogItems)
set catalogItems=0
--关闭文件并删除xtra实例
end
在上面的例子中，数据文件在输入收集了新的目录数据，但这些数据不会排序。这样，当你要检索某一条特殊的记录时，必须从头开始读遍每个记录直到找到要找的记录为止。当文件中的记录逐渐增多时，重新获取某条记录所需的时间便会加长。通过维护文件索引以及使用SetPosition方法在所需记录的开始处读取，便可以大大提高读取速度。在这个例子中，目录项文件是通过输入数据建立的。在你向文件添加新的目录项记录的同时，你可以向列表中增加一个索引条目，这个索引条目只包括你以后想用来检索记录的数据区域和记录号码。在这时，你需要使用项目号，下面的Lingo代码便是向索引中添加项目号:
on newIndexEntry itemNumber
global itemNumberIndex
if voidP(itemNumberIndex) then
set itemNumberIndex=[:]
set lastRecord=integer(field"Record Count")
setaProp(itemNumberIndex,itemNumber, lastRecord+1)
end if
end
索引比起数据文件来要小得多，因此你可以使用电影中的域来存储索引列表。或者将索引列表写入到另一个文件中。
建立固定长度的记录，并使用SetPosition的方法在特定位置上开始也可以加快读取的速度。例如，如果你的每个记录均为30个字符，那么SetPosition（300）将把文件指针放置到第十一条记录前，因为在它前面共有10×30个字符，也就是有十条记录。要编写固定长度记录的最简单的方法便是把字符串的末尾填满不会显示在数据中的某个字符。例如使用“^”符号填充长度为30个字符的记录。
GardenHose,XRP2132,32.99^^^^^
只要你确信所选择的字符不会在数据本身中使用到，那么当在记录中阅读时，将可以十分方便地使用项分界符除去填充的字符。如：
set the itemdelimiter="^"
put item 1 of recordReadIn
GardenHose,XRP2132,32.99
由于将“^”定义为项分界符，所以在项目1中的所有“^”符号都被忽略。
在固定长度的记录中，你所选择的固定长度应该是能够允许用户输入的最大长度。因为用RETURN符号计算记录的长度，这样，假设你的记录长度为30，那么在其中包含了29个数据字符和一个RETURN符号。
在下面的例子中，使用记录号来从一个文件中读取一条记录，这个文件中包含的是固定长度为30个字符的记录：
on getRecord recordNumber
set recordLength=30
--指定记录的固定长度为30个字符，以便后面进行换算
set catalogItems=new(xtra"fileio")
openFile(catalogItems,"catafile.txt",1)
setPosition(catalogItems,recordNumbet* recordLength)
set record=readLine(catalogItems)
set the itemDelimiter="^"
set strippedRecord=item 1 of record
return strippedRecord
end
使用外部文件来保存用户数据时，会涉及到关于文件基本操作的一些问题，因此显得较为麻烦，但如果你对这种方式熟悉后，会发现它是非常灵活的。
好了，通过对这两种方式的了解，相信你对开发具有更强同用户交流能力的多媒体产品将会更有信心了。根据你的产品的具体情况来选择合适的方式。当不希望其它人随意更改保存的用户数据或数据量很小时，可以利用Director的内部字段来进行存储；当数据量很大或需要进行分类、索引时，便可以利用外部文件来进行存储。

(杨 军)