Question

I'm building an Android app with C++ library, and I have a problem with sending file path.

I have my JNI function in jni/processing.cpp :

JNIEXPORT jfloat JNICALL Java_com_my_package_path_getMyFunction
(JNIEnv *env, jobject obj, jstring param) {
    string str = env->GetStringUTFChars(param, 0);
    string filePath = "src/textfile/";
    return getResult(str, filePath);
}

and getResult() is a member function of jni/src/library/myclass.cpp.

I have several text files under jni/src/textfiles/, and I want to send this path to getResult() function as a parameter. Since processing.cpp is in jni/ folder, I set path as src/textfile/, but it doesn't work. (getResult() function can't find the path)

I've been tried filePath = "../../textfile/" which is relative path from jni/src/library/myclass.cpp, and it also doesn't work.

However, all my other JNI functions (not using file path) are working fine.

Is there anyone who can help? Should I use absolute path? Then, how can I get it?

Was it helpful?

Solution

I found the solution by myself.

According to Chris' comment above, I put my text files into the assets folder.

I tried to access assets folder from JNI (like this), but somewhat it didn't work.

So I read files in Java, and store files again into internal storage. Since we know the data/data/your_app_package_name/ is the internal storage path, I can read files from JNI.

Here's the code how I read files from assets and store to internal storage :

AssetManager assetManager = getResources().getAssets();
    String[] files = null;

    try {
        files = assetManager.list("Files");
    } catch (Exception e) {
        Log.d(MYLOG, "ERROR : " + e.toString());
    }

    for (int i = 0; i < files.length; i++) {
        InputStream in = null;
        OutputStream out = null;
        FileOutputStream fileOutStream = null;
        try {
            Log.d(MYLOG, "file names : " + files[i]);

            in = assetManager.open("Files/" + files[i]);
            out = new FileOutputStream(getApplicationContext().getFilesDir() + files[i]);

            File file = new File(getApplicationContext().getFilesDir(), files[i]);

            byte[] buffer = new byte[65536 * 2];
            int read;
            while ((read = in.read(buffer)) != -1) {
                out.write(buffer, 0, read);
            }
            in.close();
            in = null;

            out.flush();
            fileOutStream = new FileOutputStream(file);
            fileOutStream.write(buffer);
            out.close();
            out = null;
            Log.d(MYLOG, "File Copied in storage");
        } catch (Exception e) {
            Log.d(MYLOG, "ERROR: " + e.toString());
        }
    }

I'm not sure this is the right solution, but it worked well! :)

OTHER TIPS

I don't know if it's actually possible to get the path to the assets directory with JNI (I'm not an expert, though): my uninformed opinion is that the Android developers might want us to access the files by proxy anyway, and it might be a good idea doing so to ensure future compatibility.

You can probably get the naked path with a trick similar to the one you explained in your answer, and get the assets path from java then pass it to C via JNI.

Regardless, I think that the performance (not to mention space) efficient way to access the files in Assets from jni is to use the AAssetManagerfunction:

Android read text file from asset folder using C (ndk)

and

Get relative path to file within project in JNI

Still, +1 to the accepted answer for the ingenuity :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top