Android NDK中的文件操作

Rya*_*heu 63 c file-io java-native-interface android-ndk

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

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

Tim*_*ger 62

使用JNI,文件IO在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)!");
}
Run Code Online (Sandbox Code Playgroud)

这是在我的手机上运行后的结果(带有SD卡):

$ adb -d shell cat /sdcard/hello.txt
HELLO WORLD!
Run Code Online (Sandbox Code Playgroud)

  • 是否可以以只读模式打开驻留在资产中的文件? (2认同)

Ita*_*Ita 60

其他答案都是正确的.您可以使用FILE和通过NDK打开文件fopen,但不要忘记为其授予权限.

在Android清单中:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
Run Code Online (Sandbox Code Playgroud)


小智 23

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

  • 这确实非常重要 (3认同)

Som*_*Tim 21

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

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

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

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

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

祝好运.

  • ...留给读者作为练习?如果我无法从堆栈溢出复制粘贴代码,我该怎么做? (2认同)