首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

J2ME JSR 75 FileConnection API 詳解:本地文件系統訪問完全指南

     編輯:J2ME

前言:突破 RMS 限制的鑰匙

JSR 75 定義了兩個可選包:PIM (個人信息管理) 和 FC (FileConnection)。FC API 讓 MIDlet 能夠訪問設備本地文件系統 (內存卡、手機內存),讀寫大文件、與其他應用共享數據、支持用戶導入導出,徹底解決 RMS 體積小、無文件系統交互的痛點。

FC API vs RMS 定位對比

核心類與接口

  • javax.microedition.io.file.FileConnection:核心接口,繼承 StreamConnection,提供文件/目錄操作
  • javax.microedition.io.file.FileSystemRegistry:管理根目錄枚舉、監聽器註冊
  • javax.microedition.io.file.FileSystemListener:監聽文件系統變化 (插拔卡、文件增刪改)
  • 異常:IllegalModeException (模式錯誤)、ConnectionClosedException (操作已關閉連接)

設備支持檢測


String version = System.getProperty("microedition.io.file.FileConnection.version");
if (version != null) {
    // 支持 JSR 75 FC API,版本通常為 "1.0"
} else {
    // 不支持,降級使用 RMS
}
// 注意:摩托羅拉早期設備使用 com.motorola.io.file 包,API 幾乎相同

文件讀寫完整實戰

1. 打開文件 (三種模式)


FileConnection fconn = null;
try {
    // READ / READ_WRITE / WRITE
    fconn = (FileConnection) Connector.open("file:///a/mobile/audio/playlist.txt", Connector.READ_WRITE);
    
    // 關鍵:open() 不拋異常即使文件不存在,必須調用 exists() 判斷
    if (!fconn.exists()) {
        fconn.create(); // 創建文件
    }
} catch (IOException e) { /* 處理 */ }

2. 讀取文件 (DataInputStream 模式)


private void loadPlaylist() {
    FileConnection fconn = null;
    DataInputStream dis = null;
    try {
        fconn = (FileConnection) Connector.open("file:///a/mobile/audio/playlist.txt", Connector.READ);
        if (!fconn.exists()) return;
        
        dis = fconn.openDataInputStream();
        musicList.removeAllElements();
        String path;
        while ((path = dis.readUTF()) != null) { // 協議:路徑、名稱、大小
            String name = dis.readUTF();
            long size = dis.readLong();
            MusicInfo info = new MusicInfo(path, name, size);
            musicList.addElement(info);
        }
    } catch (EOFException e) {
        // 正常讀取結束
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try { if (dis != null) dis.close(); } catch (IOException ignored) {}
        try { if (fconn != null) fconn.close(); } catch (IOException ignored) {}
    }
}

3. 寫入文件 (DataOutputStream + 原子替換)


private void savePlaylist() {
    FileConnection fconn = null;
    DataOutputStream dos = null;
    try {
        fconn = (FileConnection) Connector.open("file:///a/mobile/audio/playlist.txt", Connector.READ_WRITE);
        
        // 原子替換策略:刪除舊文件 → 創建新文件 → 寫入
        if (fconn.exists()) fconn.delete();
        fconn.create();
        
        dos = fconn.openDataOutputStream();
        for (int i = 0; i < musicList.size(); i++) {
            MusicInfo info = (MusicInfo) musicList.elementAt(i);
            dos.writeUTF(info.path);
            dos.writeUTF(info.name);
            dos.writeLong(info.size);
        }
        dos.flush(); // 強制刷新到存儲介質
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try { if (dos != null) dos.close(); } catch (IOException ignored) {}
        try { if (fconn != null) fconn.close(); } catch (IOException ignored) {}
    }
}

目錄操作與枚舉


// 判斷是否目錄
boolean isDir = fconn.isDirectory();

// 創建目錄 (需完整路徑)
FileConnection dir = (FileConnection) Connector.open("file:///a/mobile/myfolder", Connector.READ_WRITE);
dir.mkdir();

// 列舉目錄內容
Enumeration enum = fconn.list(); // 返回 String 枚舉 (文件名/目錄名)
while (enum.hasMoreElements()) {
    String name = (String) enum.nextElement();
    // 處理 name...
}
// 也可強制轉型:String[] list = (String[]) fconn.list(); (實現細節依賴設備)

文件系統監聽器:響應 SD 卡插拔


public class StorageListener implements FileSystemListener {
    public void stateChanged(int state, String rootName) {
        switch (state) {
            case FileSystemListener.ROOT_ADDED:
                // SD 卡插入,rootName 如 "file:///b/"
                scanNewStorage(rootName);
                break;
            case FileSystemListener.ROOT_REMOVED:
                // SD 卡拔出
                invalidateStorage(rootName);
                break;
        }
    }
}

// 註冊監聽
FileSystemRegistry.addFileSystemListener(new StorageListener());

安全模型與簽名現實

維度RMSFileConnection (FC)
存儲容量~100KB-1MB受限於存儲卡/閃存 (MB-GB)
數據結構記錄集 (byte[])完整文件系統 (目錄/文件)
跨應用共享不支持 (AUTHMODE_ANY 僅同套件)原生支持 (文件級共享)
文件操作無創建/刪除/重命名/列表/屬性
強制實現是 (MIDP 1.0+)可選 (需設備支持 JSR 75)
安全模型套件隔離簽名域 + 用戶授權提示

現實建議:涉及 FC API 的商業應用,**必須申請運營商/廠商簽名**,否則用戶體驗不可接受。

最佳實踐總結

  1. 路徑規範:使用 FileSystemRegistry.listRoots() 獲取根目錄,拼接相對路徑,避免硬編碼
  2. 異常安全:所有流/連接在 finally 中關閉
  3. 原子寫入:臨時文件寫入完成 → 重命名覆蓋,防止寫入中斷損壞數據
  4. 大文件分塊:大文件讀寫分塊處理,避免 OOM
  5. 編碼統一:文本文件統一 UTF-8,二進制文件自定義協議

FC API 讓 J2ME 具備了真正的文件級數據管理能力,是豐富應用功能的關鍵擴展。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
簽名狀態讀取權限寫入權限用戶提示
未簽名/自簽名每次提示允許禁止極其頻繁,體驗極差
運營商簽名允許 (可配置)允許 (可配置)首次/會話提示
廠商/根簽名靜默允許靜默允許無提示