Yoric
Yoric

Reputation: 4093

Creating temporary files in Android with NDK

I am currently working on a C-based, NDK-based, Android application. This application needs to create temporary files. On a regular Linux system, I would use tmpfile to ensure that these files are properly created in a temporary directory and cleaned-up at process end.

However, my investigations on various Android devices seem to indicate that

Now, I'm sure that I could hack something together, but seeing that the SDK offers context.getCacheDir and File.createTempFile for Java applications, I hope that there is an equivalent at C-level.

Does anyone know of a good reliable and cross-Android method for creating a temporary file?

Upvotes: 26

Views: 13375

Answers (5)

Vilius Sutkus '89
Vilius Sutkus '89

Reputation: 804

  1. Obtain path to cache directory on application's startup using a ContentProvider.
  2. Implement tmpfile function with the same signature as POSIX's tmpfile.
  3. Call mkstemp from your tmpfile function using the previously obtained cache directory

Packaged it as .aar, so it could be consumed through gradle.

https://github.com/ViliusSutkus89/tmpfile-Android

Upvotes: 0

Matthew Grivich
Matthew Grivich

Reputation: 451

Below is the GetMethodID / CallObjectMethod procedure that Ertebolle refers to. It is necessary if you are working with a pure native app (such as built by Visual Studio 2015) and cannot use java code.

std::string android_temp_folder( struct android_app *app ) {
    JNIEnv* env;
    app->activity->vm->AttachCurrentThread( &env, NULL );

    jclass activityClass = env->FindClass( "android/app/NativeActivity" );
    jmethodID getCacheDir = env->GetMethodID( activityClass, "getCacheDir", "()Ljava/io/File;" );
    jobject cache_dir = env->CallObjectMethod( app->activity->clazz, getCacheDir );

    jclass fileClass = env->FindClass( "java/io/File" );
    jmethodID getPath = env->GetMethodID( fileClass, "getPath", "()Ljava/lang/String;" );
    jstring path_string = (jstring)env->CallObjectMethod( cache_dir, getPath );

    const char *path_chars = env->GetStringUTFChars( path_string, NULL );
    std::string temp_folder( path_chars );

    env->ReleaseStringUTFChars( path_string, path_chars );
    app->activity->vm->DetachCurrentThread();
    return temp_folder;
}

Upvotes: 8

nak
nak

Reputation: 107

mkstemp is available in the NDK under stdlib.h

Upvotes: 0

Ruediger
Ruediger

Reputation: 271

As far as I know there is no global /tmp in android, you should use the cache dir. Use getCacheDir() to get the "tmp" dir.

http://developer.android.com/guide/topics/data/data-storage.html#filesInternal and http://developer.android.com/reference/android/content/Context.html#getCacheDir%28%29

Upvotes: 0

Ertebolle
Ertebolle

Reputation: 2342

The best way we've found is to call Context.getCacheDir on startup, get its path with getAbsolutePath, then call a JNI function to store that path in a global. Any function that wants to create a temporary file simply appends a suitable temporary file name to that path.

If you really want to fetch it from JNI another alternative would be to pass in a Context to a JNI function and use a bunch of GetMethodID / CallObjectMethod stuff to call back into Java to getCacheDir, but the former approach is a lot simpler.

Unfortunately, there does not appear to be a more elegant solution at the moment.

Upvotes: 15

Related Questions