如何从Android Oreo(8.1)或更高版本中的URI获取文件路径

ryo*_*osu 5 android uri android-contentresolver android-fileprovider android-8.1-oreo

预期的行为

当我选择存储在"下载"中的文件时,它应该能够检索其文件名和路径

实际行为

当我选择存储在"下载"中的文件时,它返回null.

重现问题的步骤

  1. 调用pick文件方法时,它会在Android中显示文件夹
  2. 转到下载,选择一个文件
  3. 它从URI获取实际路径时返回null

这是我实现的代码

public static String getPath(final Context context, final Uri uri) {
   String id = DocumentsContract.getDocumentId(uri);
   if (!TextUtils.isEmpty(id)) {
      if (id.startsWith("raw:")) {
          return id.replaceFirst("raw:", "");
      }
      try {
         final boolean isOreo = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
         String stringContentURI;
         Uri contentUri;
         if(isOreo){ 
            stringContentURI = "content://downloads/my_downloads";
         }else{
            stringContentURI = "content://downloads/public_downloads";
         }
         contentUri = ContentUris.withAppendedId(
                    Uri.parse(stringContentURI), Long.valueOf(id));
         return getDataColumn(context, contentUri, null, null);
      } catch (NumberFormatException e) {
         return null;
      }
   }
}

public static String getDataColumn(Context context, Uri uri, String selection,
                                   String[] selectionArgs) {
    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {   column};
    try {
        cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
                null);
        if (cursor != null && cursor.moveToFirst()) {
            final int index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

但是,从Android中的其他文件夹中选择文件时,它正在工作

请指教.感谢大家 :)

ryo*_*osu 14

目前,获取路径的最佳方法是:

从URI获取物理文件作为InputStream, ContentResolver.openInputStream()允许您在不知道其真实路径的情况下访问文件的内容

String id = DocumentsContract.getDocumentId(uri);
InputStream inputStream = getContentResolver().openInputStream(uri);
Run Code Online (Sandbox Code Playgroud)

然后将其写为缓存存储中的临时文件

File file = new File(getCacheDir().getAbsolutePath()+"/"+id);
writeFile(inputStream, file);
String filePath = file.getAbsolutePath();
Run Code Online (Sandbox Code Playgroud)

以下是将临时文件写入缓存存储的方法

void writeFile(InputStream in, File file) {
     OutputStream out = null;
     try {
          out = new FileOutputStream(file);
          byte[] buf = new byte[1024];
          int len;
          while((len=in.read(buf))>0){
            out.write(buf,0,len);
          }
     } catch (Exception e) {
          e.printStackTrace();
     }
     finally {
          try {
            if ( out != null ) {
                 out.close();
            }
            in.close();
          } catch ( IOException e ) {
               e.printStackTrace();
          }
     }
}
Run Code Online (Sandbox Code Playgroud)

不确定它是否是最佳方法,但代码工作正常:D

  • 这是一种救生解决方案。谢谢。但是我仍然想知道为什么谷歌的家伙不能保持简单。我认为要获取文件路径需要进行大量工作。 (2认同)