# How to save data to the ML2 Filesystem

**URL:** <https://forum.magicleap.cloud/t/how-to-save-data-to-the-ml2-filesystem/3260>\
**Category:** Native Development\
**Tags:** file-storage\
**Created:** [March 8, 2024, 11:45pm UTC](https://forum.magicleap.cloud/t/how-to-save-data-to-the-ml2-filesystem/3260 "2024-03-08T23:45:57Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![jvivernois2](https://avatars.discourse-cdn.com/v4/letter/j/dbc845/32.png) [@jvivernois2](https://forum.magicleap.cloud/u/jvivernois2)\
**Post date:** [March 8, 2024, 11:45pm UTC](https://forum.magicleap.cloud/t/how-to-save-data-to-the-ml2-filesystem/3260/1 "2024-03-08T23:45:57Z")

</div>

**ML2 OS version** : 1.4.1  
**MLSDK version** : 1.5.0  
**Host OS** : MacOS

Hello,

I am currently developing my first App for the ML2 and struggle at some points. Currently I try saving the Frames from the Depth Camera and the Data from the regular Camera (RGB) to the local Filesystem on the ML2. However I have not yet been very successful with the standard c++ way of using `ofstream`, as my `file.is_open()` is always false.

So I am wondering if this is the right way to do it and I am just missing something or if there is another way to do this. Hence, Is this the right way to do it or is there another way? And, Is there some guide in which this is explained or a sample to which I can look for help?

---

<div class="post-metadata">

**Author:** ![kbabilinski](https://sea1.discourse-cdn.com/flex019/user_avatar/forum.magicleap.cloud/kbabilinski/32/19_2.png) [@kbabilinski](https://forum.magicleap.cloud/u/kbabilinski)\
**Post date:** [March 11, 2024, 7:31pm UTC](https://forum.magicleap.cloud/t/how-to-save-data-to-the-ml2-filesystem/3260/2 "2024-03-11T19:31:09Z")

</div>

Saving frames as images in an Android app is a common task, but it's important to use the appropriate methods provided by the Android framework rather than standard C++ techniques like `ofstream`. Android has specific file system access rules, especially starting with Android 10 (API level 29) due to scoped storage, which can prevent traditional file I/O from working as expected.

Here's a general approach to saving images on Android:

1. 
  - Request the necessary permissions - in your `AndroidManifest.xml` file, such as `WRITE_EXTERNAL_STORAGE`

2. **Use Android's `MediaStore` API** to save images. This API provides a standard way to save images to the shared storage without needing to request file permissions.
3. **Handle file paths and URIs** correctly. Android 10 introduces [scoped storage](https://source.android.com/docs/core/storage/scoped), which means you can't directly access file paths. Instead, you should use URIs provided by the `MediaStore` API.

For more detailed guidance, you might want to check out Android's official documentation or look for tutorials on using the `MediaStore` API to save images.

---

<div class="post-metadata">

**Author:** ![jvivernois2](https://avatars.discourse-cdn.com/v4/letter/j/dbc845/32.png) [@jvivernois2](https://forum.magicleap.cloud/u/jvivernois2)\
**Post date:** [March 18, 2024, 10:15am UTC](https://forum.magicleap.cloud/t/how-to-save-data-to-the-ml2-filesystem/3260/3 "2024-03-18T10:15:15Z")

</div>

Thank you for your response! However, as this is not only my first ML App, but my first Android App in general I still struggle to use the `MediaStorage API`. From what I found out it appears that I have to use JNI. Correct? Because I struggle to integrate JNI into my Project. Especially using/calling `JavaVM` and `JNIEnv`. Can you provide me any insights in how to properly integrate this in the ML App structure?

---

<div class="post-metadata">

**Author:** ![kbabilinski](https://sea1.discourse-cdn.com/flex019/user_avatar/forum.magicleap.cloud/kbabilinski/32/19_2.png) [@kbabilinski](https://forum.magicleap.cloud/u/kbabilinski)\
**Post date:** [March 18, 2024, 4:38pm UTC](https://forum.magicleap.cloud/t/how-to-save-data-to-the-ml2-filesystem/3260/4 "2024-03-18T16:38:39Z")

</div>

You may have luck finding more information regarding file saving and integrating JNI into your Android project on Android's forums and documentation. Note, you do not have to use scoped storage if you are saving to your local application path.

Here is some background information on understanding JavaVM and JNIEnv

- **JavaVM:** This represents the Java Virtual Machine within your native code. A `JavaVM` pointer allows you to start your Java code from your C++. You'll usually obtain this pointer from within a JNI function.
- **JNIEnv:** This is an interface pointer that provides the functionality for interacting with the Java environment. You'll use `JNIEnv` to perform actions like:
  - Finding and calling Java classes/methods.
  - Converting between Java and C++ data types.
  - Accessing Java objects.

Additional Resources:

[Add C and C++ code to your project | Android Studio | Android Developers](https://developer.android.com/studio/projects/add-native-code)  
[JNI · android/ndk Wiki · GitHub](https://github.com/android/ndk/wiki/JNI)  
[JNI tips | Android NDK | Android Developers](https://developer.android.com/training/articles/perf-jni)

Regarding writing files:

This is just a brief overview but if you want to access local app storage you can do so using JNIEnv inside the C++ class. (pseudo code)

```c++
std::string getInternalFilesDir() {
    JNIEnv* env = getJNIEnv(); // Obtain JNI environment
    jobject context = getContext(); // Get the application context

    jmethodID getFilesDirId = env->GetMethodID(env->GetObjectClass(context), 
                                               "getFilesDir", "()Ljava/io/File;");
    jobject filesDir = env->CallObjectMethod(context, getFilesDirId); 

    jmethodID getAbsolutePath = env->GetMethodID(env->GetObjectClass(filesDir), 
                                                 "getAbsolutePath", "()Ljava/lang/String;");
    jstring pathStr = (jstring)env->CallObjectMethod(filesDir, getAbsolutePath);

    const char* nativePath = env->GetStringUTFChars(pathStr, 0);
    std::string filePath = nativePath;
    env->ReleaseStringUTFChars(pathStr, nativePath);

    return filePath;
}

```

Then you could use it inside your application like so:

```auto
// ... include statements from above ...

int main() {

  // ... existing code ...

  // Get and construct filepath
  std::string internalFilesDir = getInternalFilesDir();
  std::string filePath = internalFilesDir + "/my_text_file.txt";

  // Write to file
  std::ofstream outFile(filePath);
  if (outFile.is_open()) {
      outFile << "This is the content of my text file.\n";
      outFile.close();
  } else {
      // Handle error, unable to open file
  } 

  // ... rest of your application code ...

}

```

---

<div class="post-metadata">

**Author:** ![jvivernois2](https://avatars.discourse-cdn.com/v4/letter/j/dbc845/32.png) [@jvivernois2](https://forum.magicleap.cloud/u/jvivernois2)\
**Post date:** [March 25, 2024, 9:26am UTC](https://forum.magicleap.cloud/t/how-to-save-data-to-the-ml2-filesystem/3260/5 "2024-03-25T09:26:05Z")

</div>

Thanks a lot for the explanation. It seems I was really close with what I tried, but my main Issue with calling/obtaining the JavaVm and JNIEnv remains. If I want to use them I need to get them from somewhere and I cannot figure out how to do this. Sadly most resources on the internet are for integrating native code in the java application, but not calling java methods from within native code.

My main issue is with, what is in your Pseudocode as `getJNIEnv()` and `getContext()`. I cannot just create/initialize a new environment and also my experiments with `JNIEXPORT` and `JNICALL` have not yielded any results. So how do I obtain those? Could you provide me more Info on how to do this? This would be much appreciated

---

<div class="post-metadata">

**Author:** ![aheaney](https://avatars.discourse-cdn.com/v4/letter/a/f08c70/32.png) [@aheaney](https://forum.magicleap.cloud/u/aheaney)\
**Post date:** [March 26, 2024, 1:57am UTC](https://forum.magicleap.cloud/t/how-to-save-data-to-the-ml2-filesystem/3260/6 "2024-03-26T01:57:29Z")

</div>

It should be fine to use stl classes to write to a file. (std::ofstream) How are you implementing your application? Are you building a native application using Android's standard NativeActivity? Assuming you're using NativeActivity, the implementation of android\_native\_app\_glue should provide a reference to an android\_app struct in the android\_main callback function. [android\_app Struct Reference &nbsp;|&nbsp; Android Developers](https://developer.android.com/reference/games/game-activity/structandroid/app#structandroid__app)

You should be able to get a pointer to JNIEnv and even the app's external data path as a string from the config on the android\_app struct.  
[https://developer.android.com/reference/games/game-activity/struct/game-activity#externaldatapath](https://developer.android.com/reference/games/game-activity/struct/game-activity#externaldatapath)

---

<div class="post-metadata">

**Author:** ![kbabilinski](https://sea1.discourse-cdn.com/flex019/user_avatar/forum.magicleap.cloud/kbabilinski/32/19_2.png) [@kbabilinski](https://forum.magicleap.cloud/u/kbabilinski)\
**Post date:** [May 27, 2024, 5:46pm UTC](https://forum.magicleap.cloud/t/how-to-save-data-to-the-ml2-filesystem/3260/7 "2024-05-27T17:46:48Z")

</div>


