【问题标题】:Android - writing/saving files from native code onlyAndroid - 仅从本机代码写入/保存文件
【发布时间】:2012-07-02 21:58:12
【问题描述】:

我正在尝试构建一个使用 NDK 的 NativeActivity 工具的 Android 应用程序。 我有以下结构:

  • 一堆原生共享库安装在/system/vendor/<company>;我在工作 使用自定义构建的 Android 图像,因此库没有问题 适当的权限和一切
  • 使用NativeActivity 的几个应用程序又依赖于库 上面提到的

/system/vendor 中安装的库和我的应用程序使用了几个 配置文件。使用标准 C API 读取它们没有问题 fopen/fclose。但是那些库和我的应用程序也需要存储一些文件 作为它们操作的结果,例如配置、一些运行时参数、校准 数据,日志文件等。在存储文件时存在一个小问题,因为我不允许写入/system/vendor/...(因为“/system/...”下的文件系统是只读安装的,我不想破解)。

那么创建和存储这些文件的最佳方式是什么? 最好的“符合安卓”的存储区?

我一直在阅读 android-ndk Google 小组中的几个线程,并且在这里提到了 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)。

【问题讨论】:

    标签: android android-ndk


    【解决方案1】:

    对于相对较小的文件(应用程序配置文件、参数文件、日志文件等) 最好使用内部应用私有存储,即/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);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-22
      • 2015-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多