17

I am working on an app where I want to be able to export and import some data from the app, on a .txt file. The minimum API of the app is 21.

The export part works well, but I am having trouble with the import part.

I open the file explorer :

butImportPatient.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View view) {
         Intent intent = new Intent();
         intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
         intent.setType("*/*");
         startActivityForResult(intent, IMPORTPATIENT_ACTIVITY_REQUEST_CODE);
    }
});

This looks like it is working.

But my onActivityResult doesn't work, I didn't find how I can get the file from the Uri.

For now, here is my code :

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

      if (requestCode == IMPORTPATIENT_ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK) {
            File file = new File(data.getData().getPath()) ;
            String path = file.getAbsolutePath() ;
            StringBuilder text = new StringBuilder();

            try {
                BufferedReader br = new BufferedReader(new FileReader(path));
                String line;

                while ((line = br.readLine()) != null) {
                    text.append(line);
                    text.append("\n");

                }
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            AlertDialog.Builder builder = new AlertDialog.Builder(this) ;
            builder.setMessage(path)
                    .show() ;

        }
 }

It is a mix of multiple posts I saw here, but none seems to work.

I get this path :

/document/home:List.txt

It creates FileNotFoundException. How can I get the real path of the file ?

Rohit Singh
  • 16,950
  • 7
  • 90
  • 88
Tonher
  • 195
  • 2
  • 2
  • 10

1 Answers1

19

I didn't find how I can get the file from the Uri.

There is no file. ACTION_OPEN_DOCUMENT and ACTION_GET_CONTENT do not open a file. They open a document. That document might be a file. It might not. That Uri might point to:

  • A local file on external storage
  • A local file on internal storage for the other app
  • A local file on removable storage
  • A local file that is encrypted and needs to be decrypted on the fly
  • A stream of bytes held in a BLOB column in a database
  • A piece of content that needs to be downloaded by the other app first
  • ...and so on

How can I get the real path of the file ?

You don't.

If you wish to only accept files, integrate a file chooser library instead of using ACTION_OPEN_DOCUMENT or ACTION_GET_CONTENT. Just bear in mind that filesystem access to external storage is limited on Android 10+.

If you use ACTION_GET_CONTENT, and the scheme of the Uri that you get is file, then getPath() will be a filesystem path.

Otherwise, you need to understand that you have no idea where the document is coming from, and stop thinking in terms of "real path of the file". Use ContentResolver and openInputStream() to make a copy of the content to some file that you control, then work with that file.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Thanks for the answer ! I admit I grabbed code without really knowing what it meant. I will check that website, it seems really intersting. – Tonher Mar 11 '18 at 15:13
  • Which Intent should I use to get the real path? Maybe reading the file itself on the app. But getting a real file... or a real path? – Amg91 Nov 25 '18 at 20:56
  • 1
    @Amg91: "Which Intent should I use to get the real path?" -- there is none. Quoting myself from my answer, "If you wish to only accept files, integrate a [file chooser library](https://android-arsenal.com/tag/35)". – CommonsWare Nov 25 '18 at 21:12
  • Then how to use the Uri properly ? – Foxhunt Jun 17 '21 at 19:28
  • 1
    @Foxhunt: That depends on what you are trying to do with it. For example, you could use `ContentResolver` and `openInputStream()` to read in the content. – CommonsWare Jun 17 '21 at 20:17
  • I case of Hybrid app (with webview) where I need to fetch a large binary file from Javascript, how would I do it? (in a regular web-app I would do fetch(file_url)) – Avner Moshkovitz Oct 27 '21 at 23:29
  • @AvnerMoshkovitz: I have no idea, sorry. – CommonsWare Oct 27 '21 at 23:33
  • @CommonsWare, based on your reputation you have lots of experience in mobile development. I'm a newbe in this field, so I'm asking naively. Consider a case of a hybrid web-app that uses the user's own data file that is stored on the phone. I'm sure I'm not the first to tackle this need. Is this something that just can't be handled by a Hybrid app? Or maybe I'm missing something very fundemental.. – Avner Moshkovitz Oct 28 '21 at 00:25
  • @AvnerMoshkovitz: "based on your reputation you have lots of experience in mobile development" -- yes, but I have zero recent experience with hybrid app frameworks, including whatever hybrid app framework you happen to be using. "I'm sure I'm not the first to tackle this need" -- it would be the responsibility of the developers of the hybrid app framework to expose the sorts of things that I describe in my answer. So, research how Apache Cordova or whatever hybrid app framework you are using addresses this problem. – CommonsWare Oct 28 '21 at 10:53