Android - 仅从本机代码写入/保存文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11294487/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android - writing/saving files from native code only
提问by celavek
I'm trying to build an Android app which makes use of the NativeActivity
facility of the NDK.
I'm having the following structure:
我正在尝试构建一个利用NativeActivity
NDK 功能的 Android 应用程序。我有以下结构:
- a bunch of native shared libraries installed in
/system/vendor/<company>
; I'm working with a custom built Android image so there's no problem having the libraries there with proper permissions and everything - a couple of applications using the
NativeActivity
that depend in turn on the libraries mentioned above
- 安装了一堆本地共享库
/system/vendor/<company>
;我正在使用自定义构建的 Android 映像,因此在那里拥有具有适当权限的库和所有内容都没有问题 - 使用 的几个应用程序
NativeActivity
依次依赖于上述库
The libraries installed in the /system/vendor and my applications use a couple of
configuration files. There's no problem reading them using the standard C API
fopen/fclose
. But those libraries and my application also need to store some files
as the result of their operation, like configuration, some run-time parameters, calibration
data, log files etc. With the storing of the files there is a slight issue as I'm not allowed to write into /system/vendor/...
(as the file system under "/system/..." is mounted read-only and I do not want to hack on that).
安装在 /system/vendor 和我的应用程序中的库使用了几个配置文件。使用标准 C API 阅读它们没有问题
fopen/fclose
。但是这些库和我的应用程序还需要存储一些文件作为其操作的结果,如配置、一些运行时参数、校准数据、日志文件等。 文件的存储有一个小问题,因为我不允许写入/system/vendor/...
(因为“/system/...”下的文件系统以只读方式安装,我不想对此进行修改)。
So what would be the best way to create and store those files and where would be the best "conforming with Android" storage area ?
那么创建和存储这些文件的最佳方式是什么,最好的“符合 Android”的存储区域在哪里?
I've been reading a couple of threads in the android-ndk Google group and here on SO that mention either the internal application private storageor the external SD card, but as I do not have extended experience with Android I'm not sure what would be the proper approach. If the approach involves some specific Android API a small code example in C++ would be very helpful; I've seen a couple of examples involving Java and JNI (e.g. in this SO question) but I would like to stay away from that right now.
Also there seems to be a problem with using from C++ the native activity's
internalDataPath/externalDataPath
pair (a bug that makes them be always NULL).
我一直在阅读 android-ndk Google 组和这里的几个线程,其中提到了内部应用程序私有存储或外部 SD 卡,但由于我没有使用 Android 的扩展经验,我不确定是什么将是正确的方法。如果该方法涉及某些特定的 Android API,则使用 C++ 编写的小代码示例将非常有帮助;我已经看到了几个涉及 Java 和 JNI 的例子(例如在这个 SO question 中),但我现在想远离那个。从 C++ 使用本机活动的internalDataPath/externalDataPath
对似乎也存在问题
(一个使它们始终为 NULL 的错误)。
回答by celavek
For relatively small files(application config files, parameter files, log files etc.)
is best to use the internal application private storage, that is /data/data/<package>/files
.
The external storage if it exists at all (being it SD card or not) should be used for large files that do not need frequent access or updates.
对于相对较小的文件(应用程序配置文件、参数文件、日志文件等),最好使用内部应用程序私有存储,即/data/data/<package>/files
. 外部存储(无论是否存在 SD 卡)应该用于不需要频繁访问或更新的大文件。
For the external data storage the native application has to "request" the correct permissions in the application's AndroidManifest.xml
:
对于外部数据存储,本机应用程序必须“请求”应用程序的正确权限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>
For the internal application private storage fopen/fclose
(or C++ stream equivalents if available) API could be used. Following example illustrates using the Android NDK AssetManager
to retrieve and read a configuration file. The file must be placed into the assets
directory inside the native application's project folder so that the NDK build could pack them inside the APK. The internalDataPath/externalDataPath
bug I was mentioning in the question was fixed for the NDK r8 version.
对于内部应用程序私有存储fopen/fclose
(或 C++ 流等效项,如果可用)可以使用 API。以下示例说明使用 Android NDKAssetManager
检索和读取配置文件。该文件必须放在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);
}
}
}