Android NDK中的文件操作

时间:2010-01-02 21:40:16

标签: c file-io java-native-interface android-ndk

出于性能原因,我使用Android NDK主要在C中创建应用程序,但似乎fopen等文件操作在Android中无法正常运行。每当我尝试使用这些功能时,应用程序崩溃。

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

5 个答案:

答案 0 :(得分:60)

使用JNI在Android上正常运行文件IO。也许您正在尝试使用错误路径打开文件而不检查返回代码?我修改了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!

答案 1 :(得分:58)

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

在Android清单中:

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

答案 2 :(得分:22)

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

答案 3 :(得分:21)

我还可以验证fopen()是否正常工作,但如果您尝试访问应用程序资源或资源文件夹中的文件,则。我建议,为了避免重新发明轮子,你可以在资产文件夹中粘贴你想要随​​应用程序一起提供的任何资产,然后将它们打包出来进行分发。

在assets文件夹中,您需要执行以下两种操作之一,具体取决于文件是否由打包程序压缩。两者都使用AssetManager方法,您可以从context / app获取AssetManager。文件名总是相对于资产文件夹,顺便说一下:如果您的资产文件夹中有一个文件“foo.png”,则打开“foo.png”,之类的“资产” /foo.png”。

  1. 如果文件未被压缩(即,它是未经压缩的扩展之一,如.png),您可以从AssetManager.openFd()获取文件描述符并将其传递给C ++ 。然后你可以使用fdopen(dup(fd),“r”);将文件作为文件打开*。请注意你必须fseek()到偏移量,并自己跟踪文件的长度。你真的得到整个资产包的文件句柄,你感兴趣的文件只是一个小部分。

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

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

    祝你好运。

答案 4 :(得分:0)

除了设置在此问题的答案中指定的正确权限之外,我还要在此处的答案中加上两美分,请确保授予您的应用程序访问操作系统中存储的权限。权限菜单可能因手机而异,一种简单的访问方法是转到“设置”菜单,然后搜索“权限”。这将使您有机会授予您的应用程序许可权,以便从NDK代码访问存储(即sdcard目录)。