2010-01-02 14 views
57

Uso el Android NDK para hacer una aplicación principalmente en C por motivos de rendimiento, pero parece que las operaciones de archivos como fopen no funcionan correctamente en Android. Cada vez que intento usar estas funciones, la aplicación falla.Operaciones de archivos en Android NDK

¿Cómo creo/escribo en un archivo con el NDK de Android?

+1

Lo sentimos, olvidamos actualizar esto. La raíz del problema no era obtener permisos para leer/escribir. Un problema similar también puede ser causado por tener la tarjeta SD montada y luego intentar abrir un archivo en ella. – RyanCheu

+0

tengo el mismo problema con usted, ¿lo ha solucionado? –

Respuesta

51

Todo lo anterior es correcto. Puede abrir un archivo a través del NDK usando FILE y fopen. PERO ... No olvides dar un permiso para ello. en el Android manifestar colocar una

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

¿Dónde colocará esta línea en el archivo de manifiesto? – Dhasneem

+0

En manifiesto http://developer.android.com/guide/topics/manifest/uses-permission-element.html –

+0

¡Gracias, funciona! Y también descubrí que las actualizaciones en el archivo de manifiesto solo tendrán efecto después de volver a instalar la aplicación. A veces, el eclipse no volverá a instalar la aplicación para usted. Borro la aplicación en mi teléfono y la vuelvo a instalar usando eclipse. –

57

El archivo IO funciona bien en Android usando JNI. ¿Quizás estás tratando de abrir un archivo con una ruta incorrecta y no verificar el código de retorno? Modifiqué el ejemplo de hello-jni para demostrar que, de hecho, es posible abrir el archivo y escribir en él. Espero que esto ayude.

/* 
* 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)!"); 
} 

aquí está el resultado después de correr en mi teléfono (con una tarjeta SD):

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

¡Gracias, eso funciona! Creo que mi problema fue que no estaba usando una ruta completa para mi comando fopen. – RyanCheu

+2

¿Sería posible abrir un archivo que reside en activos en modo de solo lectura? – dzhelil

+1

Abrir activos usando el NDK es más complicado, pero describo los pasos necesarios [aquí] (http://stackoverflow.com/questions/2651816/reading-resource-files-from-my-own-apk-in-android-native -ambiente/2663962 # 2663962). –

18

También puede verificar que fopen() funciona correctamente, pero no si estás tratando de acceder a un archivo en la carpeta de recursos o activos de la aplicación. Recomiendo, para evitar tener que reinventar la rueda, que coloque los activos que desea enviar con su aplicación en la carpeta de activos, donde se empaquetarán para su distribución.

En el caso de carpeta de activos, debe hacer una de estas dos cosas, dependiendo de si el archivo fue comprimido por el empaquetador. Ambos usan los métodos de AssetManager, y usted puede obtener AssetManager del contexto/aplicación. Los nombres de archivo siempre son relativos a la carpeta de activos, por cierto: si tiene un archivo "foo.png" directamente en la carpeta de activos, abriría "foo.png" no algo así como "assets/foo.png" .

  1. Si el archivo no se ha comprimido (es decir, es una de las extensiones que no se comprimen, como .png), se puede obtener un descriptor de archivo de AssetManager.openFd() y pasarlo a C++. Entonces puedes usar fdopen (dup (fd), "r"); para abrir el archivo como un ARCHIVO *. Tenga en cuenta que debe fseek() para el desplazamiento, y realizar un seguimiento de la longitud del archivo usted mismo. Realmente está obteniendo un identificador de archivo para todo el paquete de activos, y su archivo de interés es solo una pequeña parte.

  2. Si su archivo está comprimido, necesita usar el lector de flujo de Java: AssetManager.open() le proporciona un InputStream en el que puede leer el archivo. Esto es un PITA porque no puede consultar (AFAIK) el tamaño del archivo; Ejecuto un paso de preproceso en mi carpeta de activos que genera una lista de todos los archivos con sus respectivos tamaños para que pueda saber, por ejemplo, qué tan grande de un búfer para asignar.

Si el archivo es un recurso, es posible que tenga que pasar por la clase de recursos para acceder a ella, aunque parece que los recursos también se empaquetan en el mismo paquete de activos. El recurso tiene una llamada a openRawResource() para obtener el InputStream y una llamada a openRawResourceFd() para obtener el descriptor del archivo, como el anterior.

Buena suerte.

+0

Nota de seguimiento: El "obtener un descriptor de archivo de AssetManager.openFd()" resulta ser una mala forma, no es parte del bendito SDK. Resulta que funciona en todos los teléfonos actuales, pero no se garantiza que continúe funcionando. Obtener la ruta al archivo .APK resulta no ser difícil, y se deja como un ejercicio para el lector que se preocupa por tener un código NDK completamente kosher. – SomeCallMeTim

18

Asegúrese de utilizar la llamada Java getExternalStorageDirectory() para obtener la ruta real a la sdcard ya que los dispositivos más nuevos no se limitan a asignarla a "/ sdcard".En ese caso, intentar usar una ubicación codificada de "/ sdcard" fallará.

+3

Esto es muy importante – KaiserJohaan