Android NDK 中的文件操作

出于性能方面的原因,我使用 Android NDK 来制作一个主要用 C 语言编写的应用程序,但似乎诸如 fopen 之类的文件操作在 Android 中不能正常工作。每当我尝试使用这些函数时,应用程序就会崩溃。

如何使用 Android NDK 创建/写入文件?

104886 次浏览

文件 IO 在使用 JNI 的 Android 上运行良好。也许您试图打开一个路径错误的文件,但是没有检查返回代码?我修改了 hello-jni 示例,以证明确实可以打开文件并对其进行写操作。希望这个能帮上忙。

/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <string.h>
#include <jni.h>
#include <stdio.h>


/* This is a trivial JNI example where we use a native method
* to return a new VM String. See the corresponding Java source
* file located at:
*
*   apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java
*/
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
FILE* file = fopen("/sdcard/hello.txt","w+");


if (file != NULL)
{
fputs("HELLO WORLD!\n", file);
fflush(file);
fclose(file);
}


return (*env)->NewStringUTF(env, "Hello from JNI (with file io)!");
}

下面是在我的手机上(使用 SD 卡)运行后的结果:

$ adb -d shell cat /sdcard/hello.txt
HELLO WORLD!

我还可以验证 fopen ()是否正确工作,但是如果您试图访问应用程序的资源或资产文件夹中的文件,则使用 没有。我建议,为了避免重新发明轮子,你可以将任何你想随应用程序一起发布的资产放在资产文件夹中,在那里它们将被打包发布。

在资产文件夹的情况下,您需要做两件事情中的一件,这取决于文件是否被打包器压缩。两者都使用 AssetManager 方法,您可以从上下文/应用程序获得 AssetManager。文件名总是相对于资产文件夹,顺便说一句: 如果你有一个文件“ foo.png”直接在资产文件夹中,你会打开“ foo.png”,没有类似于“ asset/foo.png”。

  1. 如果文件没有被压缩(也就是说,它是一个没有被压缩的扩展名,比如。Png) ,您可以从 AssetManager.openFd ()获得一个文件描述符,并将其传递给 C + + 。然后可以使用 fdopen (dup (fd) ,“ r”) ; 以文件 * 的形式打开该文件。注意,必须 ffind ()到偏移量,并自己跟踪文件的长度。您实际上获得了整个资产包的文件句柄,并且您感兴趣的文件只是其中的一小部分。

  2. 如果您的文件是压缩的,那么您需要使用 Java 流阅读器: AssetManager.open ()为您提供了一个 InputStream,您可以在其中读取文件。这是一个 PITA,因为你不能查询(AFAIK)文件大小; 我在我的资产文件夹上运行一个预处理步骤,生成一个所有文件的列表,这样我就可以知道它们各自的大小,例如,分配多大的缓冲区。

如果您的文件是一个资源,您可能需要通过 Resource 类来访问它,尽管看起来资源也被打包到相同的资产包中。Resource 有一个 openRawResource ()调用来获取 InputStream,以及一个 openRawResourceFd ()调用来获取文件描述符,如上所述。

祝你好运。

其他答案都是正确的。您可以使用 FILEfopen通过 NDK 打开一个文件,但是不要忘记为它放置一个权限。

在 Android 的清单位置:

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

确保使用 JavagetExternalStorageDirectory()调用获取到 sdcard 的真实路径,因为较新的设备不能简单地将其映射到“/sdcard”。在这种情况下,尝试使用“/sdcard”的硬编码位置将会失败。

我想在这里的答案中加上我的两点意见,除了设置在这个问题的答案中指定的正确权限之外,确保给你的应用程序访问操作系统中的存储的权限。权限菜单可以在不同的电话之间更改,一个简单的方法是进入设置菜单,然后搜索“权限”这将给你一个机会给你的应用程序权限访问存储(即 sdcard 目录)从 NDK 代码。