栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 移动开发 > Android

Android7.0以上Uri转路径的方法实现(已验证)

Android 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android7.0以上Uri转路径的方法实现(已验证)

网络上看到过很多种Uri转路径的方法,可基本上都只适用于很少的Uri值,可能没有结果(例如,对于由MediaStore索引的非本地文件),也可能没有可用的结果(例如,对于可移动存储上的文件)。

解决方法

使用ContentResolver和openInputStream()在Uri标识的内容上获取InputStream。在控制的文件上使用InputStream和FileOutputStream复制内容,然后使用该文件。

代码如下:

private static String getFilePathForN(Context context, Uri uri) {
  try {
    Cursor returnCursor = context.getContentResolver().query(uri, null, null, null, null);
    int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
    returnCursor.moveToFirst();
    String name = (returnCursor.getString(nameIndex));
    File file = new File(context.getFilesDir(), name);
    InputStream inputStream = context.getContentResolver().openInputStream(uri);
    FileOutputStream outputStream = new FileOutputStream(file);
    int read = 0;
    int maxBufferSize = 1 * 1024 * 1024;
    int bytesAvailable = inputStream.available();
    int bufferSize = Math.min(bytesAvailable, maxBufferSize);
    final byte[] buffers = new byte[bufferSize];
    while ((read = inputStream.read(buffers)) != -1) {
      outputStream.write(buffers, 0, read);
    }
    returnCursor.close();
    inputStream.close();
    outputStream.close();
    return file.getPath();
  } catch (Exception e) {
    e.printStackTrace();
  }
  return null;
}

附上全系统的代码:


public class PathUtils {
  
  private static String getFilePathForN(Context context, Uri uri) {
    try {
      Cursor returnCursor = context.getContentResolver().query(uri, null, null, null, null);
      int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
      returnCursor.moveToFirst();
      String name = (returnCursor.getString(nameIndex));
      File file = new File(context.getFilesDir(), name);
      InputStream inputStream = context.getContentResolver().openInputStream(uri);
      FileOutputStream outputStream = new FileOutputStream(file);
      int read = 0;
      int maxBufferSize = 1 * 1024 * 1024;
      int bytesAvailable = inputStream.available();

      int bufferSize = Math.min(bytesAvailable, maxBufferSize);

      final byte[] buffers = new byte[bufferSize];
      while ((read = inputStream.read(buffers)) != -1) {
 outputStream.write(buffers, 0, read);
      }
      returnCursor.close();
      inputStream.close();
      outputStream.close();
      return file.getPath();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }

  
  public static String getPath(final Context context, final Uri uri) throws Exception {

    final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
    final boolean isN = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;

    if (isN) {
      return getFilePathForN(context, uri);
    }

    // documentProvider
    if (isKitKat && documentsContract.isdocumentUri(context, uri)) {
      // ExternalStorageProvider
      if (isExternalStoragedocument(uri)) {
 final String docId = documentsContract.getdocumentId(uri);
 final String[] split = docId.split(":");
 final String type = split[0];

 if ("primary".equalsIgnoreCase(type)) {
   return Environment.getExternalStorageDirectory() + "/" + split[1];
 }

      }
      // DownloadsProvider
      else if (isDownloadsdocument(uri)) {

 final String id = documentsContract.getdocumentId(uri);
 final Uri contentUri = ContentUris.withAppendedId(
     Uri.parse("content://downloads/public_downloads"), StringUtils.toLong(id));

 return getDataColumn(context, contentUri, null, null);
      }
      // MediaProvider
      else if (isMediadocument(uri)) {
 final String docId = documentsContract.getdocumentId(uri);
 final String[] split = docId.split(":");
 final String type = split[0];

 Uri contentUri = null;
 if ("image".equals(type)) {
   contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
 } else if ("video".equals(type)) {
   contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
 } else if ("audio".equals(type)) {
   contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
 }

 final String selection = "_id=?";
 final String[] selectionArgs = new String[] {
     split[1]
 };

 return getDataColumn(context, contentUri, selection, selectionArgs);
      }
    }
    // MediaStore (and general)
    else if ("content".equalsIgnoreCase(uri.getScheme())) {
      return getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
      return uri.getPath();
    }

    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 column_index = cursor.getColumnIndexOrThrow(column);
 return cursor.getString(column_index);
      }
    } catch (IllegalArgumentException e){
      //do nothing
    } finally {
      if (cursor != null)
 cursor.close();
    }
    return null;
  }

  public static boolean isExternalStoragedocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
  }

  public static boolean isDownloadsdocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
  }

  public static boolean isMediadocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
  }
}

参考资料:https://stackoverflow.com/questions/42508383/illegalargumentexception-column-data-does-not-exist

另发现一篇,亲测,Android 4.4到Android 10可用,测试的系统有VIVO、OPPO、MIUI、EMUI...

解决的国内产商问题:华为的黄色图标管理器,他返回了4.4的标准的Uri了,不是4.4以上的标准的Uri,导致解析的时候,判断到版本 > 4.4,然后用了4.4以上的标准的解析,然后失败了,并非不回调。 

直接可用的代码片段:

public class FileUtils {
 
  private Context context;
 
  public FileUtils(Context context) {
    this.context = context;
  }
 
  public String getFilePathByUri(Uri uri) {
    // 以 file:// 开头的
    if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
      return uri.getPath();
    }
    // 以/storage开头的也直接返回
    if (isOtherdocument(uri)) {
      return uri.getPath();
    }
    // 版本兼容的获取!
    String path = getFilePathByUri_BELOWAPI11(uri);
    if (path != null) {
      LogUtils.d("getFilePathByUri_BELOWAPI11获取到的路径为:" + path);
      return path;
    }
    path = getFilePathByUri_API11to18(uri);
    if (path != null) {
      LogUtils.d("getFilePathByUri_API11to18获取到的路径为:" + path);
      return path;
    }
    path = getFilePathByUri_API19(uri);
    LogUtils.d("getFilePathByUri_API19获取到的路径为:" + path);
    return path;
  }
 
  private String getFilePathByUri_BELOWAPI11(Uri uri) {
    // 以 content:// 开头的,比如 content://media/extenral/images/media/17766
    if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
      String path = null;
      String[] projection = new String[]{MediaStore.Images.Media.DATA};
      Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
      if (cursor != null) {
 if (cursor.moveToFirst()) {
   int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
   if (columnIndex > -1) {
     path = cursor.getString(columnIndex);
   }
 }
 cursor.close();
      }
      return path;
    }
    return null;
  }
 
  private String getFilePathByUri_API11to18(Uri contentUri) {
    String[] projection = {MediaStore.Images.Media.DATA};
    String result = null;
    CursorLoader cursorLoader = new CursorLoader(context, contentUri, projection, null, null, null);
    Cursor cursor = cursorLoader.loadInBackground();
    if (cursor != null) {
      int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
      cursor.moveToFirst();
      result = cursor.getString(column_index);
      cursor.close();
    }
    return result;
  }
 
  private String getFilePathByUri_API19(Uri uri) {
    // 4.4及之后的 是以 content:// 开头的,比如 content://com.android.providers.media.documents/document/image%3A235700
    if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
      if (documentsContract.isdocumentUri(context, uri)) {
 if (isExternalStoragedocument(uri)) {
   // ExternalStorageProvider
   String docId = documentsContract.getdocumentId(uri);
   String[] split = docId.split(":");
   String type = split[0];
   if ("primary".equalsIgnoreCase(type)) {
     if (split.length > 1) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
     } else {
return Environment.getExternalStorageDirectory() + "/";
     }
     // This is for checking SD Card
   }
 } else if (isDownloadsdocument(uri)) {
   //下载内容提供者时应当判断下载管理器是否被禁用
   int stateCode = context.getPackageManager().getApplicationEnabledSetting("com.android.providers.downloads");
   if (stateCode != 0 && stateCode != 1) {
     return null;
   }
   String id = documentsContract.getdocumentId(uri);
   // 如果出现这个RAW地址,我们则可以直接返回!
   if (id.startsWith("raw:")) {
     return id.replaceFirst("raw:", "");
   }
   if (id.contains(":")) {
     String[] tmp = id.split(":");
     if (tmp.length > 1) {
id = tmp[1];
     }
   }
   Uri contentUri = Uri.parse("content://downloads/public_downloads");
   LogUtils.d("测试打印Uri: " + uri);
   try {
     contentUri = ContentUris.withAppendedId(contentUri, Long.parseLong(id));
   } catch (Exception e) {
     e.printStackTrace();
   }
   String path = getDataColumn(contentUri, null, null);
   if (path != null) return path;
   // 兼容某些特殊情况下的文件管理器!
   String fileName = getFileNameByUri(uri);
   if (fileName != null) {
     path = Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName;
     return path;
   }
 } else if (isMediadocument(uri)) {
   // MediaProvider
   String docId = documentsContract.getdocumentId(uri);
   String[] split = docId.split(":");
   String type = split[0];
   Uri contentUri = null;
   if ("image".equals(type)) {
     contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
   } else if ("video".equals(type)) {
     contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
   } else if ("audio".equals(type)) {
     contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
   }
   String selection = "_id=?";
   String[] selectionArgs = new String[]{split[1]};
   return getDataColumn(contentUri, selection, selectionArgs);
 }
      }
    }
    return null;
  }
 
  private String getFileNameByUri(Uri uri) {
    String relativePath = getFileRelativePathByUri_API18(uri);
    if (relativePath == null) relativePath = "";
    final String[] projection = {
 MediaStore.MediaColumns.DISPLAY_NAME
    };
    try (Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null)) {
      if (cursor != null && cursor.moveToFirst()) {
 int index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME);
 return relativePath + cursor.getString(index);
      }
    }
    return null;
  }
 
  private String getFileRelativePathByUri_API18(Uri uri) {
    final String[] projection;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
      projection = new String[]{
   MediaStore.MediaColumns.RELATIVE_PATH
      };
      try (Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null)) {
 if (cursor != null && cursor.moveToFirst()) {
   int index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.RELATIVE_PATH);
   return cursor.getString(index);
 }
      }
    }
    return null;
  }
 
  private String getDataColumn(Uri uri, String selection, String[] selectionArgs) {
    final String column = MediaStore.Images.Media.DATA;
    final String[] projection = {column};
    try (Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null)) {
      if (cursor != null && cursor.moveToFirst()) {
 final int column_index = cursor.getColumnIndexOrThrow(column);
 return cursor.getString(column_index);
      }
    } catch (IllegalArgumentException iae) {
      iae.printStackTrace();
    }
    return null;
  }
 
  private boolean isExternalStoragedocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
  }
 
  private boolean isOtherdocument(Uri uri) {
    // 以/storage开头的也直接返回
    if (uri != null && uri.getPath() != null) {
      String path = uri.getPath();
      if (path.startsWith("/storage")) {
 return true;
      }
      if (path.startsWith("/external_files")) {
 return true;
      }
    }
    return false;
  }
 
  private boolean isDownloadsdocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
  }
 
  private boolean isMediadocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
  }
}

调用 getFilePathByUri(Uri uri) 即可获得最终的路径。 

到此这篇关于Android7.0以上Uri转路径的方法实现(已验证)的文章就介绍到这了,更多相关Android7 Uri转路径内容请搜索考高分网以前的文章或继续浏览下面的相关文章希望大家以后多多支持考高分网!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/154489.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号