1 引言 本文檔講述了FileConnection API [JSR-075],並簡要介紹了該包中包含的MIDlet範例以及諾基亞特有的一些實現細節。本文檔假定讀者熟悉Java™編程,並具有移動信息設備描述 (Mobile Information Device Profile, MIDP)編程的基礎,MIDP編程基礎可參見諾基亞論壇中的文檔MIDP 1.0: Introduction to MIDlet Programming [MIDPPROG]。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包含兩個Java™ 2 Platform, Micro Edition (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。即使構建了此類的連接,仍可能不支持文件操作,如重命名文件或刪除文件。此外,對本地文件的訪問關係到安全、私密和系統穩定性等方面的重要問題,在實現時必須對此給予考慮。
FileConnection API [JSR-075]通過提供對文件系統的訪問以及對文件操作的支持,彌補了上述缺陷。該API假定設備中存在一個可定位的文件系統,如可移動的內存卡、閃存或其它類型的永久存儲器。該API並不是記錄管理系統(Record Management System ,RMS)的替代物,它只是對RMS的補充,從而實現MIDlet與本地應用軟件的交互。例如, MIDlet可以訪問並處理本地應用軟件先前利用內嵌數碼照相機拍下的圖象。一般情況下,這些圖象存儲在設備內存中,通過FileConnection API ,可以實現CLDC/CDC應用軟件對它們的訪問。
該API的最低要求是CLDC 1.0,因此,即使沒有用戶界面的基本J2ME設備也能實現它。但是,本文檔和MIDlet範例都假定FileConnection API是在MIDP 2.0設備上實現的。此外,該API的安全機制還在MIDP 2.0 安全架構 [SIGNMIDP]下。
由於FileConnection API 是可選的擴展項,所以,增加了一個系統屬性用於表明該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,如RFC 1738 [RFC 1738] 和RFC 2396 [RFC 2396]中的定義,URL的格式爲file:///
,其中,host通常爲空,path則以文件系統的根目錄開始,並往下擴展到一個特定文件或目錄。Symbian設備中,典型的文件URL範例如下所示:
file:///C:/Nokia/Images/Image(001).jpg
文件系統的根目錄因設備而異,由於根目錄是由設備的操作系統從邏輯上進行定義的,故它們沒有必要與物理上的內存單元對應。此外,某些諾基亞設備支持虛擬目錄,虛擬目錄實際上就是指向某個目錄的鏈接。例如,在內存卡中,拍下的圖象可能位於根目錄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的方式定義許可模式:
功能組
|
可信的第三方域
|
不可信的域
|
默認設置
|
允許的設置
|
默認設置
|
允許的設置
|
Read User Data
|
Oneshot
|
Session, Blanket,
|
Oneshot
|
Oneshot, No
|
Access
|
Oneshot, No
|
Write User Data Access
|
Oneshot
|
Session, Blanket, Oneshot, No
|
No
|
Oneshot, No
|
表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的兼容性。
屬性
|
局部屬性
|
描述
|
fileconn.dir.photos
|
fileconn.dir.photos.name
|
該屬性指向的目錄存儲集成照相機拍下的相片或其它圖象。
|
fileconn.dir.videos
|
fileconn.dir.videos.name
|
與上面類似,但是存儲的內容是視頻。默認情況下,下載的視頻也保存在該目錄下。
|
fileconn.dir.tones
|
fileconn.dir.tones.name
|
鈴聲或其它類似的音頻文件存儲在該目錄下。
|
fileconn.dir.memorycard
|
fileconn.dir.memorycard.name
|
在內存卡可用的情況下,該屬性指向內存卡的根目錄。
|
fileconn.dir.private
|
fileconn.dir.private.name
|
MIDlet套件的專用工作目錄。
|
表2:諾基亞特有的目錄