无法从 uri 访问文件

Unable to access file from uri

我正在尝试使用存储在本地的存储访问框架访问文件并将其发送到服务器。但是每当我尝试使用 URI 获取文件时,我都会得到 NullPointerException。但是我得到了文件的 URI。但是在通过获取路径转换为文件时捕获异常。 最小 API 是 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;
        }

尝试使用以下代码获取路径:

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());
}`

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

欢迎您的用户选择他们想要的任何内容,其中不包括您可以直接访问的文件(例如,在 Google 驱动器中,在可移动存储上)。

but catches exception when converting to file by getting path

你不能"convert to file by getting path"。 content Uri 的路径部分是一组无意义的字符,用于标识特定内容。接下来,您会认为所有计算机在其本地文件系统上的路径 /questions/43818723/unable-to-access-file-from-uri 上都有一个文件,只是因为 恰好是有效的 Uri.

所以,去掉 getPath()

使用 ContentResolveropenInputStream() 获得内容的 InputStream。直接使用该流或将其与您自己的文件上的 FileOutputStream 结合使用,以创建可用作文件的内容的本地副本。

@CommonsWare 回答正确 这是代码片段

从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);

将文件从 Uri 保存到应用程序目录中的本地副本:

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();
  }