-1

I'm struggling with reading file stream inside Android environment using C++ library. I believe I set all the permissions correctly (1st figure) and I'm getting the file path using Android internal library. Would you please give me a snippet to correctly read a file using std::ifstream.getline()? For instance, I get "/document/1EF7-1509:Download/015_1440.jpg" for the image file existing in the 2nd figure under "Download" folder. This path is a raw value returned by "Intent.getData().getPath()" with "ACTION_GET_CONTENT".

extern "C" JNIEXPORT jstring JNICALL Java_com_example_testpplication_MainActivity_testGeneralEncryption(JNIEnv* env, jobject, jstring myString)
{
    const char *nativeString = env->GetStringUTFChars(myString, nullptr);
    std::string filePath = std::string(nativeString);
    std::string buffer;
    std::ifstream fStreamIn(filePath);
    if(fStreamIn.is_open())
    {
        std::getline(fStreamIn, buffer);
    }
    else
    {
        bool exists = fStreamIn.good();
        if(exists)
        {
            buffer = "Exists";
        }
        else
        {
            buffer = "Non-existing";
        }
    }
    return env->NewStringUTF((buffer + ":" + filePath).c_str());
}

enter image description here

enter image description here

enter image description here

  • One thing to watch out for is that `GetStringUTFChars()` will return a string in Java's **modified** UTF-8 format, but the underlying filesystem is likely to be using *standard* UTF-8 instead. `NewStringUTF()` also requires *modified* UTF-8, not *standard* UTF-8. Not that these will affect your example, but it is something to be aware of. Also, you are not calling `ReleaseStringUTFChars()` when done using `nativeString`. – Remy Lebeau Jan 10 '22 at 22:04
  • 1
    Your code is trying to open `/document/1EF7-1509:Download/015_1440.jpg`, but your screenshot shows the actual file path is `/storage/1EF7-1509/Download/015_1440.jpg` instead, so it makes sense why `ifstream` would fail to open it. – Remy Lebeau Jan 10 '22 at 22:08
  • 2
    `Intent.getData().getPath()` That is not a file system path. Have a look at `Intent.getData().toString()` to see the obtained content scheme uri. – blackapps Jan 10 '22 at 22:11
  • @RemyLebeau I just checked my project. There is no typo, but as you said, it still gives me a path which "looks like wrong". I will hardcode this and check again. Thank you! – Bicycle-riding Dog Jan 10 '22 at 22:12
  • @blackapps Your solution gives me a path "content://com.android.externalstorage.documents/document/1EF7-1509%3ADownload%2F015_1440.jpg" which looks promising. I will check further with the information from Remy. Thank you!. – Bicycle-riding Dog Jan 10 '22 at 22:15
  • I tried Intent.getData().getPath(), getData().toString() and hard-coded path. I also modified the characters in the toString() result in a way that it became "content://com.android.externalstorage.documents/document/1EF7-1509:Download/015_1440.jpg" and tried. None of them works. Do you have any other idea by any chance? – Bicycle-riding Dog Jan 10 '22 at 22:34
  • 1
    It is unclear what you tried with that content scheme. A content scheme is no path and you should not handle it as a path to begin with. – blackapps Jan 10 '22 at 23:29
  • Thanks. After inspired by your answers, I just googled with a different keyword and realized that I need a different approach to get the real file path. There are a lot of answers regarding this matter. So I just flagged my question that this is a duplicate. – Bicycle-riding Dog Jan 11 '22 at 08:07

1 Answers1

0

Thanks to @blackapps, I did a google with a different keyword and found below answer. Basically, my question is a duplicate.

Inspired by this answer: https://stackoverflow.com/a/49221353/1770003

The idea is, Android doesn't directly return the absolute path as other OS reports like Windows. A different approach is needed.

The approach I took is,

  1. Add this in my solution: https://android-arsenal.com/details/1/8142#!package
  2. Edit the project: https://github.com/onimur/handle-path-oz/wiki/Java-Single-Uri

In my case, I moved the caller into onRequestHandPathOz which is add by implementing "HandlePathOzListener.SingleUri".

@Override
public void onRequestHandlePathOz(PathOz pathOz, Throwable throwable)
{
    txt_pathShow.setText(testGeneralEncryption(pathOz.getPath()));
}

The method "testGeneralEncryption" is defined in the original question and pathOz.getPath() is passed as an argument to the parameter "jstring myString".