2012-07-02 25 views
22

我試圖建立一個Android應用程序,它使用NDK的NativeActivity工具。 我有以下結構:Android - 只從本地代碼寫入/保存文件

  • 一堆本地共享庫安裝在/system/vendor/<company>;我有一個定製的Android圖像加工 所以有具有 適當的權限有圖書館,一切
  • 沒有問題,一對夫婦使用NativeActivity應用程序又取決於上述
提到的庫

安裝在/ system/vendor和我的應用程序中的庫使用了幾個 配置文件。使用標準C API fopen/fclose閱讀它們沒有任何問題。但是這些庫和我的應用程序也需要存儲一些文件作爲其操作的結果,例如配置,一些運行時參數,校準數據,日誌文件等。隨着文件的存儲,存在輕微的問題,因爲I '不允許寫入/system/vendor/...(因爲「/ system/...」下的文件系統是隻讀的,我不想對此進行破解)。

那麼創建和存儲這些文件的最佳方式是什麼?以及最符合Android的存儲區域的 ?

我一直在讀一對夫婦線程的Android NDK谷歌組,並在這裏,這樣既提或the internal application private storagethe external SD card,但由於我沒有經驗,擴大與Android我不知道會是什麼正確的做法。如果該方法涉及某些特定的Android API,那麼C++中的一個小代碼示例將非常有用;我見過一些涉及Java和JNI的例子(e.g. in this SO question),但我現在想遠離它。 從C++使用本地活動的 internalDataPath/externalDataPath對(a bug that makes them be always NULL)似乎也有問題。

回答

23

對於相對較小的文件(應用程序配置文件,參數文件,日誌文件等) 最好使用內部應用程序專用存儲,即/data/data/<package>/files。 外部存儲(如果存在的話)(不管是否爲SD卡)應該用於不需要頻繁訪問或更新的大文件。

對於外部數據存儲的本機應用程序必須「請求」正確的在應用程序的AndroidManifest.xml權限:

<manifest> 
    ... 
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"> 
    </uses-permission> 
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"> 
    </uses-permission> 
</manifest> 

對於內部應用專用存儲fopen/fclose(或C++流當量如果可用)API可以是用過的。以下示例說明如何使用Android NDK AssetManager來檢索並讀取配置文件。該文件必須放置在本地應用程序項目文件夾內的assets目錄中,以便NDK構建可以將它們打包到APK中。我在這個問題中提到的internalDataPath/externalDataPath錯誤是針對NDK r8版本修復的。

... 
void android_main(struct android_app* state) 
{ 
    // Make sure glue isn't stripped 
    app_dummy(); 

    ANativeActivity* nativeActivity = state->activity;        
    const char* internalPath = nativeActivity->internalDataPath; 
    std::string dataPath(internalPath);        
    // internalDataPath points directly to the files/ directory         
    std::string configFile = dataPath + "/app_config.xml"; 

    // sometimes if this is the first time we run the app 
    // then we need to create the internal storage "files" directory 
    struct stat sb; 
    int32_t res = stat(dataPath.c_str(), &sb); 
    if (0 == res && sb.st_mode & S_IFDIR) 
    { 
     LOGD("'files/' dir already in app's internal data storage."); 
    } 
    else if (ENOENT == errno) 
    { 
     res = mkdir(dataPath.c_str(), 0770); 
    } 

    if (0 == res) 
    { 
     // test to see if the config file is already present 
     res = stat(configFile.c_str(), &sb); 
     if (0 == res && sb.st_mode & S_IFREG) 
     { 
      LOGI("Application config file already present"); 
     } 
     else 
     { 
      LOGI("Application config file does not exist. Creating it ..."); 
      // read our application config file from the assets inside the apk 
      // save the config file contents in the application's internal storage 
      LOGD("Reading config file using the asset manager.\n"); 

      AAssetManager* assetManager = nativeActivity->assetManager; 
      AAsset* configFileAsset = AAssetManager_open(assetManager, "app_config.xml", AASSET_MODE_BUFFER); 
      const void* configData = AAsset_getBuffer(configFileAsset); 
      const off_t configLen = AAsset_getLength(configFileAsset); 
      FILE* appConfigFile = std::fopen(configFile.c_str(), "w+"); 
      if (NULL == appConfigFile) 
      { 
       LOGE("Could not create app configuration file.\n"); 
      } 
      else 
      { 
       LOGI("App config file created successfully. Writing config data ...\n"); 
       res = std::fwrite(configData, sizeof(char), configLen, appConfigFile); 
       if (configLen != res) 
       { 
        LOGE("Error generating app configuration file.\n"); 
       } 
      } 
      std::fclose(appConfigFile); 
      AAsset_close(configFileAsset); 
     } 
    } 
}