【问题标题】:File Operations in Android NDKAndroid NDK 中的文件操作
【发布时间】:2010-12-31 20:47:48
【问题描述】:

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

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

【问题讨论】:

  • 抱歉忘记更新了。问题的根源是没有获得读/写权限。安装 sdcard 然后尝试打开其中的文件也可能导致类似的问题。

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


【解决方案1】:

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

在 Android manifest 地方:

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

【讨论】:

  • 谢谢,它有效!而且我还发现清单文件上的更新只有在您重新安装应用程序后才会生效。有时 Eclipse 不会为您重新安装应用程序。我删除了手机上的应用程序并使用 eclipse 重新安装。
【解决方案2】:

文件 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 命令没有使用完整路径。
  • 是否可以以只读模式打开驻留在资产中的文件?
  • 使用 NDK 打开资产比较复杂,但我描述了所需的步骤here
【解决方案3】:

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

【讨论】:

  • 这确实很重要
  • 运行 adb shell "ls / -l | grep sdcard" 来确定您的设备也在哪里映射 /sdcard 目录(用于调试目的)
  • 我没有使用 getExternalStorageDirectory,而是使用了 getenv("EXTERNAL_STORAGE") 但它不起作用。尽管在 adb shell 上 $EXTERNAL_STORAGE/sdcard/。我使用的是安卓 7.1。我应该使用getExternalStorageDirectory 获取路径吗?
【解决方案4】:

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

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

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

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

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

祝你好运。

【讨论】:

  • 后续说明:“从 AssetManager.openFd() 获取文件描述符”结果是错误的形式——它不是祝福 SDK 的一部分。它恰好适用于所有当前的手机,但不能保证继续工作。事实证明,获取 .APK 文件的路径并不难,留给希望拥有完全符合 kosher NDK 代码的读者作为练习。
  • ...留给读者作为练习?如果我不能从堆栈溢出中复制粘贴代码,我该怎么做?
  • ...通过从另一个答案复制代码?或者只是自己做研究。这个答案是七岁。无论如何,从您自己的新闪亮测试代码构建一些东西可能很好,因为我在编写此代码时可能正在为 Android 2.x 开发。
  • 为了记录,我主要是想开个玩笑。我只是讨厌我在大学的课本中的“读者练习”,这些课本似乎总是漏掉那些我最难弄清楚的问题的答案。
  • 要牢记的有用法则。即使是我本人,我的枯燥幽默有时也会被忽视,在互联网上更是如此。
【解决方案5】:

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

【讨论】:

    猜你喜欢
    • 2021-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-29
    • 1970-01-01
    • 2019-12-13
    • 1970-01-01
    相关资源
    最近更新 更多