0

I am trying to access a file using Storage Access Framework which I have stored in locally and send it to server. but when ever I try to get file using URI I get NullPointerException. However I get the URI of file. but catches exception when converting to file by getting path. Minimum API is 17

uriString = content://com.android.providers.downloads.documents/document/349

     warantyButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(Intent. ACTION_OPEN_DOCUMENT );
                    intent.addCategory(Intent.CATEGORY_OPENABLE);
                    intent.setType("*/*");
                    Intent i = Intent.createChooser(intent, "File");
                    getActivity().startActivityForResult(i, FILE_REQ_CODE);
                   //Toast.makeText(getContext(),"Files",Toast.LENGTH_SHORT).show();
                }
            });


     @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (requestCode == FILE_REQ_CODE) {
                if (resultCode == RESULT_OK) {
                    String path="";
                    Uri uri = data.getData();
                    if (uri != null) {
                        try {
                            file = new File(getPath(getContext(),uri));
                            if(file!=null){
                                ext = getMimeType(uri);
                                sendFileToServer(file,ext);
                            }

                        } catch (Exception e) {
                            Toast.makeText(getContext(),getString(R.string.general_error_retry),Toast.LENGTH_SHORT).show();
                            e.printStackTrace();
                        }
                    }
                }

            }

        }



public static String getPath(Context context, Uri uri) throws URISyntaxException {
        if ("content".equalsIgnoreCase(uri.getScheme())) {
            String[] projection = { "_data" };
            Cursor cursor = null;

            try {
                cursor = context.getContentResolver().query(uri, projection, null, null, null);
                int column_index = cursor.getColumnIndexOrThrow("_data");
                if (cursor.moveToFirst()) {
                    return cursor.getString(column_index);
                }
            } catch (Exception e) {
                // Eat it
            }
        }
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }

            return null;
        }
Mehvish Ali
  • 732
  • 2
  • 10
  • 34

3 Answers3

4

I am trying to access a file using Storage Access Framework which I have stored in locally and send it to server.

Your users are welcome to choose anything they want, which does not include files that you can access directly (e.g., in Google Drive, on removable storage).

but catches exception when converting to file by getting path

You cannot "convert to file by getting path". The path portion of a content Uri is a meaningless set of characters that identifies the particular piece of content. Next, you will think that all computers have a file on their local filesystem at the path /questions/43818723/unable-to-access-file-from-uri, just because https://stackoverflow.com/questions/43818723/unable-to-access-file-from-uri happens to be a valid Uri.

So, get rid of getPath().

Use ContentResolver and openInputStream() to get an InputStream on the content. Either use that stream directly or use it in conjunction with a FileOutputStream on your own file, to make a local copy of the content that you can use as a file.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
0

@CommonsWare answer is correct here is code snippet

To read file content from Uri :

        // Use ContentResolver to access file from Uri
    InputStream inputStream = null;
    try {
        inputStream = mainActivity.getContentResolver().openInputStream(uri);
        assert inputStream != null;

        // read file content
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String mLine;
        StringBuilder stringBuilder = new StringBuilder();
        while ((mLine = bufferedReader.readLine()) != null) {
            stringBuilder.append(mLine);
        }
        Log.d(TAG, "reading file :" + stringBuilder);

To save file from Uri to local copy inside your app dir :

String dirPath = "/data/user/0/-your package name -/newLocalFile.name"

try (InputStream ins = mainActivity.getContentResolver().openInputStream(uri)) {

            File dest = new File(dirPath);

            try (OutputStream os = new FileOutputStream(dest)) {
                byte[] buffer = new byte[4096];
                int length;
                while ((length = ins.read(buffer)) > 0) {
                    os.write(buffer, 0, length);
                }
                os.flush();
      } catch (Exception e) {
            e.printStackTrace();
      }

  } catch (Exception e) {
         e.printStackTrace();
  }

            
Josef Vancura
  • 1,053
  • 10
  • 18
  • After the file is saved as local copy in the app dir, is it possible to restart the app and read from this file programatically,without having to manually select the file? – Avner Moshkovitz Nov 12 '21 at 07:50
  • Ok, I now understand that if the file is saved to the file system, e.g. in the internal storage of the app, then the file exists and can be read when the app restarts (obviously), but a content uri from previous run, has no meaning when the app restarts. – Avner Moshkovitz Nov 30 '21 at 00:42
-2

Try Below Code For Getting Path:

public String getPath(Uri uri) throws URISyntaxException {
    final boolean needToCheckUri = Build.VERSION.SDK_INT >= 19;
    String selection = null;
    String[] selectionArgs = null;
    // Uri is different in versions after KITKAT (Android 4.4), we need to
    // deal with different Uris.
    if (needToCheckUri && DocumentsContract.isDocumentUri(mainActivity, uri)) {
        if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            return Environment.getExternalStorageDirectory() + "/" + split[1];
        } else if (isDownloadsDocument(uri)) {
            final String id = DocumentsContract.getDocumentId(uri);
            uri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
        } else if (isMediaDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];
            if ("image".equals(type)) {
                uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            } else if ("video".equals(type)) {
                uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
            } else if ("audio".equals(type)) {
                uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
            }
            selection = "_id=?";
            selectionArgs = new String[] {
                    split[1]
            };
        }
    }
    if ("content".equalsIgnoreCase(uri.getScheme())) {
        String[] projection = {
                MediaStore.Images.Media.DATA
        };
        Cursor cursor = null;
        try {
            cursor = mainActivity.getContentResolver()
                    .query(uri, projection, selection, selectionArgs, null);
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            if (cursor.moveToFirst()) {
                return cursor.getString(column_index);
            }
        } catch (Exception e) {

        }
    } else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }
    return null;
}`/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is ExternalStorageProvider.
 */
public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is DownloadsProvider.
 */
public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is MediaProvider.
 */
public static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
}`
Akash Shah
  • 15
  • 4
  • 1
    This is worse than useless. It makes assumptions about the internal implementation of various providers, and those assumptions do not have to hold between Android OS versions or even devices from different manufacturers. It also does not handle most `content` `Uri` values, such as those from apps using `FileProvider`. – CommonsWare May 06 '17 at 11:01