1. 引言 FileConnection API 是一个受限 API ,例如,它具有安全上的限制。因此,读者还必须熟悉 MIDP 2.0 安全架构的概念;诺基亚论坛中的文档 MIDP 2.0: Tutorial On Signed MIDlets [SIGNMID] 介绍了安全模型和签名过程。
FileConnection API 在 JSR-75(PDA Optional Packages for the J2ME Platform) 中定义, JSR-75 包含两个 J2ME 可选包,用于支持 PDA 之类的设备的功能。可选包提供了对个人信息管理 (PIM API) 数据库和本地文件系统 (FileConnection API) 的访问。这两个包完全独立,因此,设备可以包含其中任意一个包,也可以同时包含两个包。
2 FileConnection API
2.1 简介
在 J2ME 设备中,可以利用通用连接架构 (Generic Connection Framework , GCF) ,通过各种连接类型特有的 Connection 接口实现,来处理 I/O 操作。构建不同的 Connection 扩展要使用适合于不同连接类型的 URL ,如 http:// , sockets:// 等。原则上讲, GCF 通常足以支持文件连接,但是, GCF 不是 J2ME 或 MIDP 的必选项,大多数实现中都没有包含 GCF 。即使构建了此类的连接,仍可能不支持文件操作,如重命名文件或删除文件。此外,对本地文件的访问关系到安全、私密和系统稳定性等方面的重要问题,在实现时必须对此给予考虑。
JSR-075 通过提供对文件系统的访问以及对文件操作的支持,弥补了上述缺陷。该 API 假定设备中存在一个可定位的文件系统,如可移动的内存卡、闪存或其它类型的永久存储器。该 API 并不是 RMS 的替代物,它只是对 RMS 的补充,从而实现 MIDlet 与本地应用软件的交互。例如, MIDlet 可以访问并处理本地应用软件先前利用内嵌数码照相机拍下的图像。一般情况下,这些图像存储在设备内存中,通过 JSR-075 ,可以实现 CLDC/CDC 应用软件对它们的访问。
该 API 的最低要求是 CLDC 1.0 ,因此,即使没有用户界面的基本 J2ME 设备也能实现它。但是,本文档和 MIDlet 范例都假定 JSR-075 是在 MIDP 2.0 设备上实现的。此外,该 API 的安全机制还在 MIDP 2.0 安全架构 [SIGNMIDP] 下。
由于 JSR-075 是可选的扩展项,所以,增加了一个系统属性用于表明该 API 是否存在。系统属性 microedition.io.file.FileConnection.version 包含实现的 API 版本。目前,该属性的值为 1.0 或 null , 1.0 表明该 API 的当前状态, null 则说明未使用该 API 。另外一个有用的系统属性是 file.separator ,它包含用于隔离目录的字符,其典型值为“ / ”。
该 API 非常简单,仅包含一个类、两个接口和两个异常。其中 FileConnection 接口是最为重要的部分,它扩展了 Connection 接口,提供对目录和单个文件的访问。创建 FileConnection 的实现需要使用方法 Connector.open() 。方法 open() 的参数是一个 URL ,如 RFC1738-Uniform Resource Locators (URL) 和 RFC 2396-Uniform Resource Identifiers (URI) 中的定义, URL 的格式为 file:/// ,其中, host 通常为空, path 则以文件系统的根目录开始,并往下扩展到一个特定文件或目录。 Symbian 设备中,典型的文件 URL 范例如下所示: file:///C:/Nokia/Images/Image.jpg .
注: RFC(Request For Comments) 即“请求注解”,包含了关于 Internet 的几乎所有重要的文字资料。
文件系统的根目录因设备而异,由于根目录是由设备的操作系统从逻辑上进行定义的,故它们没有必要与物理上的内存单元对应。此外,某些诺基亚设备支持虚拟目录,虚拟目录实际上就是指向某个目录的链接。例如,在内存卡中,拍下的图象可能位于根目录 e: 下的路径 file:///e:/Nokia/Images 中,此外,还有一个虚拟根目录 Images/ 指向实际的物理位置。假设 MIDlet 具有访问目录 Images/ 的权限,但却无权访问根目录 e:/ ,这种情况下,虚拟根目录将有助于更容易地定位,并可简化安全许可。
类 FileSystemRegistry 提供了方法 listRoots() ,该方法的返回值是文件系统中根目录的枚举,其中包括逻辑根目录和虚拟根目录。该 API 还考虑到了某些设备在运行期间具有添加或删除文件系统的能力。类 FileSystemRegistry 提供注册 FileSystemListener 监听器的方法,在修改设备中的根目录时,将调用该方法。建议每个应用软件都注册一个 FileSystemListener 监听器,在发生变化时,监听器将被告之发生了变化并做出适当响应。
由于 FileConnection 接口能够扩展 Connection ,并可利用 GFC 创建对象, FileConnection 与其它常见 Connection 实现之间存在着一些显著差异。其中一个最显著的差异是,即使当前文件不存在,也能成功调用 Connector.open() 。这在创建新文件或新目录时是很有必要的。但是,打开不存在文件的 InputStream 是非法的。
另一个差异是,在关闭输入或输出流后, FileConnection 仍能保持打开状态。因此,在访问文件后调用方法 FileConnction.close() 是很重要的,这样做可以保证其它应用能访问该文件。相应地,利用 OutputStream 对文件做出的修改也不会立即对文件系统可见。这取决于实际的实现以及设备的操作系统。方法 flush() 可以保证缓冲区能够被清空,并且其中的内容可以写入实际文件中。
与其它 Connection 对象的另外一个差别是,通过方法 setFileConnection() ,可以实现 FileConnection 对象的重用。该方法主要用于目录转换。其思想是,如果在特定目录中构建了 FileConnection ,则可以调用方法 list() 获得该目录的子文件和子目录的枚举。该枚举值的成员可作为参数被传递给 setFileConnection() ,之后,原始 FileConnection 就指向了这个特定的子文件或子目录。通常来说, setFileConnection() 的参数是已存在的其它子文件或目录的相对路径,或者是表示上层目录的“ .. ”参数。
另外一个针对所有 I/O 操作的常见注意事项是,必须在异于 GUI 线程的其它线程中执行 I/O 操作。在使用 FileConnection API 时,这个建议同样适用。由于安全架构的原因,与文件相关的操作可能会发生用户提示,要求用户对操作进行确认,考虑到这一点,在异于 GUI 线程的其它线程中执行 I/O 操作尤为重要。如果在 GUI 线程中执行 I/O 操作,并且需要使用用户提示,则 MIDlet 就有可能会死锁。
2.2 安全
在用 FileConnection API 开发应用软件时,考虑 API 的安全隐患是非常重要的。为了保护用户的个人数据和整个系统的安全,文件操作是受限制的。只有在获得必须的许可后,才能执行文件操作;否则,将抛出 SecurityException 异常。因此在适当的时候使用捕获 SecurityException 的语句非常重要。
MIDP 2.0 MIDlet 既可以是不可信的,也可以是可信的 [SIGNMID] 。在第一种情况下,设备无法确知 MIDlet 的由来和完整性,因此,在没有显式的用户许可时,不允许调用受限的 API 。也就是说,如果需要访问一个文件或目录,将会显示用户提示,而用户必须显式地确认该操作。
在 MIDlet 是可信的情况下,设备可以通过 X.509 证书判断 MIDlet 的由来和完整性。这些 MIDlet 可以根据安装时的安全域设置,自动地获得许可。此外, MIDlet 需要在 Java 应用描述符 (Java Application Descriptor , JAD) 文件中的属性 MIDlet-Permission 中包含文件操作许可。
共定义了下面两个有关 FileConnection API 的许可:
javax.microedition.io.Connector.file.read
javax.microedition.io.Connector.file.write
如果希望以 READ 模式打开文件,并获取文件的输入流,则第一个许可是必需的。在用类 FileSystemRegistry 注册监听器时,也需要第一个许可。如果希望以 WRITE 模式打开文件,并打开文件的输出流,则第二个许可是必需的。此外,诸如删除、修改目录之类的操作也需要写入许可。如果以 READ_WRITE 模式打开文件,则同时需要两个许可。这些许可包含在 Read User Data Access 和 Write User Data Access 功能组中。
对许可的授权或否认取决于 MIDlet 安装到的安全域。某些安全域可以完全地授权许可,而其它域则可能仅在得到显式用户同意的情况下才允许授权。实现时,可以对每个域允许的许可进行定义。但是,仍希望第三方和不可信域按照表 1 的方式定义许可模式:
<!-- [if gte vml 1]><v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"> <v:stroke joinstyle="miter"/> <v:formulas> <v:f eqn="if lineDrawn pixelLineWidth 0"/> <v:f eqn="sum @0 1 0"/> <v:f eqn="sum 0 0 @1"/> <v:f eqn="prod @2 1 2"/> <v:f eqn="prod @3 21600 pixelWidth"/> <v:f eqn="prod @3 21600 pixelHeight"/> <v:f eqn="sum @0 0 1"/> <v:f eqn="prod @6 1 2"/> <v:f eqn="prod @7 21600 pixelWidth"/> <v:f eqn="sum @8 21600 0"/> <v:f eqn="prod @7 21600 pixelHeight"/> <v:f eqn="sum @10 21600 0"/> </v:formulas> <v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"/> <o:lock v:ext="edit" aspectratio="t"/> </v:shapetype><v:shape id="_x0000_i1025" type="#_x0000_t75" style='width:414.75pt; height:69.75pt'> <v:imagedata src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\02\clip_image001.png" o:title="许可模式"/> </v:shape><![endif]--><!-- [if !vml]--> <!-- [endif]-->
<!-- [if gte vml 1]><v:shape id="_x0000_i1026" type="#_x0000_t75" style='width:414.75pt;height:43.5pt'> <v:imagedata src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\02\clip_image003.png" o:title="允许的和默认的许可模式"/> </v:shape><![endif]--><!-- [if !vml]--> <!-- [endif]-->
表 1 :允许的和默认的许可模式
表 1 实际上说明,每次创建文件或目录连接时,不可信的 MIDlet 总会弹出一个提示。此外,如果以 READ_WRITE 模式打开连接,将会出现两个提示,分别对应于两个许可 。可信的第三方 MIDlet 的情况与此类似,但是用户可以手动地把该设置改为 session ,这样,在运行 MIDlet 时,用户就会仅被询问一次。 值得注意的另外一点是,许可是以基于文件到文件的方式给出的。也就是说,用户在访问每个文件或目录时都会被提示。该范例中的 MIDlet 需要在文件系统中遍历,因此会出现多个用户提示,对于此类的 MIDlet 来说,上述情况尤其值得注意。这种情况能够有力地说明,在使用受限 API 时,为什么应该对 MIDlet 签名。
此外,关于文件访问还有另外一个层面上的局限。根据安装时赋给 MIDlet 的安全域, MIDlet 将能够访问文件系统的一个子集。这种设计可以保护用户数据,并可防止对操作系统的损害。特别地,可信的第三方和不可信域中的 MIDlet 仅能访问一组被指定的公共目录(其中包括存放图象、视频、公共文件的目录)以及每个 MIDlet 的专用目录。这是推荐使用虚拟目录的原因之一,因为,有可能允许访问根目录 Images/ ,但可能由于 MIDlet 无法访问 e: ,从而造成无法从 e:/ 切换到目录 e:/Nokia/Images/ 。
某些文件相关操作会检查是否获得了适当的安全许可,但是,在调用方法 Connector.open() 时,开发人员需要给予特别考虑。在创建 FileConnection 和授权适当的许可后,对于需要同样许可的其它操作来说,该许可仍然有效。例如,一旦为写操作创建 FileConnection ,则调用删除( delete )操作也已经被授权。如果创建的 FileConnection 仅具有对读操作的许可,则在调用方法 delete() 时,将会要求对写操作的许可,在必要时,还将出现用户提示。
方法 setFileConnection() 还将根据原始 FileConnection 的创建模式检查文件许可。这是非常合理的,因为 setFileConnection 能够改变当前连接,以便指向不同的文件或目录。
2.3 诺基亚特有的目录
在许多诺基亚设备中,一些目录是针对特定任务而设计的。例如,照相机设备在特定的“图像”目录下存储拍下的照片。为了使开发人员更加容易地访问此类目录,实现了 FileConnection API 的诺基亚设备包含额外的系统属性,以用于定位这些目录。
并不是所有设备都需要这些属性,因此,不要想当然地认为它们存在。开发人员应该注意,如果属性值为 null ,则需寻找一个替代方法。
表 2 列举了系统属性。第一列是属性名,它以 URL 的格式指向特定目录。该 URL 可以被直接传递给 Connection.open() 。第二列是一个额外的属性,它包含该目录的本地化名称。建议用第二列中的属性代替目录的通用的非本地化名称,以保持 MIDlet 与其它设备 UI 的兼容性。
<!-- [if gte vml 1]><v:shape id="_x0000_i1027" type="#_x0000_t75" style='width:415.5pt;height:165.75pt'> <v:imagedata src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\02\clip_image005.png" o:title="诺基亚特有的目录"/> </v:shape><![endif]--><!-- [if !vml]--> <!-- [endif]-->
表 2 诺基亚特有的目录
Jsr-75 包括如下两个接口和三个类:
FileConnection 访问文件和文件夹的接口 ;
FileSystemListener 添加删除根目录文件系统的状态监听的接口 ;
FileSystemRegistry 添加删除根目录文件系统的接口注册类 ;
ConnectionClosedException 当一个文件句柄的操作被调用,而文件已经被关闭时抛出的异常 ;
IllegalModeException 当操作所对应的模式不被文件打开模式支持时抛出的异常。
SD Card |
邮票大小 (32mm × 24mm × 2.1mm ) |
SDHC Card |
邮票大小 (32mm × 24mm × 2.1mm ) |
MMC Card |
邮票大小 (32mm × 24mm × 2.1mm ) |
Mini SD Card |
21.5mm × 20mm × 1.4mm |
CF Card |
纸板火柴 (43mm × 36mm × 3.3mm ) |
TF Card |
15mm × 11mm × 1mm |
手机常用括展存储卡有以下几种 :
( 一 )SD/Mini SD(Secure Digital Memory Card 安全数字卡, SD1.1 规范 ) : SD 卡是由日本松下、东芝及美国 SanDisk 公司于 1999 年 8 月共同开发研制。 Mini SD 就是 SD 的裁小版,插上专用转接器就和 SD 通用。价格上 Mini SD 比 SD 更贵。
( 二 )SDHC (High Capacity SD Memory Card , SD2.0 规范 ) 分为如下 4 个等级,不同等级能分别满足不同的应用要求:
Class 0 :包括低于 Class 2 和未标注 Speed Class 的情况;
Class 2 :能满足观看普通 MPEG4 MPEG2 的电影、 SDTV 、数码摄像机拍摄;
Class 4 :可以流畅播放高清电视( HDTV ),数码相机连拍等需求;
Class 6 :满足单反相机连拍和专业设备的使用要求;
我们可以在相应的闪存卡的表面找到一个内部写有数字的圆圈形状的图案,里面的数字代表着 class 等级,数字越高,速度越快。如果没能在闪存卡表面找到类似图案,而仅写有 SDHC 字样,那么便是 class 0 。
SDHC 最的大特点就是高容量,一般必须大于 2GB 小于等于 32GB 。而其文件系统也有了很大的变化,从以前的 FAT12 、 FAT16 提升到了 FAT32( 以往 SD 卡所使用的 FAT16 文件系统最大仅支持 2GB 的磁盘大小,无法满足大容量 SDHC 卡的要求, SDHC 卡统一必须采用 FAT32 文件系统。 ) 。另外 SDHC 至少要符合 Class 2 的速度等级,并且在卡片上必须有 SDHC 标志和速度等级标志。符合 SD 2.0 规范的 micro SD 卡,则被称作 micro SDHC 卡。 SD2.0 规范和 SD1.1 规范采用了不同的寻址方式,所以 SDHC 和 Mini SD 在彼此的插槽中互相不兼容。
( 三 )MMC(Multi Media Card ,多媒体存储卡 ) : MMC 由 SanDisk 和 Siemens 公司在 1997 年发起, MMC 卡价格和 Mini SD 相差不多。目前 MMC 在 NOKIA 智能机上用得较多。
( 四 ) 索尼记忆棒:索尼独有。这种口香糖型的存储设备几乎可以在所有的索尼影音产品上通用。
( 五 )T-Flash 卡:简称 TF 卡 , 是目前最贵的存储卡 , 比同容量 Mini SD 贵一倍 . 但它体积小 , 方便手机的外形设计 , 目前很多小巧造型的手机多支持 TF 卡。
数码相机最为常用的储存卡分以下几种:
CF 卡 (Compact Flash, 标准闪存卡 ) , CF 卡是最早推出的存储卡产品,由美国 SANDISK 于 1994 年研发成功的。一般专业单反机器都是 CF 卡。
卡片机器基本都是 SD 卡。
少部分机器用 XD 卡一般富士机器用,基本要被 SD 卡所替代。
有索尼记忆棒,只在索尼机器上用。
TF 卡 (Micro SD 卡 )MINI SD 卡有什么区别 ?
Mini SD 与 SD 是同一个类型,尽管 mini SD 卡的外形大小及接口形状与原来的 SD 卡不同,但接口等电气标准相同,确保了兼容性;