Android7.0以上如何实现Uri转路径

这篇文章给大家分享的是有关Android7.0以上如何实现Uri转路径的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

Android是什么

Android是一种基于Linux内核的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由美国Google公司和开放手机联盟领导及开发。

Android7.0以上如何实现Uri转路径

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

解决方法

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

代码如下:

privatestaticStringgetFilePathForN(Contextcontext,Uriuri){
try{
CursorreturnCursor=context.getContentResolver().query(uri,null,null,null,null);
intnameIndex=returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
returnCursor.moveToFirst();
Stringname=(returnCursor.getString(nameIndex));
Filefile=newFile(context.getFilesDir(),name);
InputStreaminputStream=context.getContentResolver().openInputStream(uri);
FileOutputStreamoutputStream=newFileOutputStream(file);
intread=0;
intmaxBufferSize=1*1024*1024;
intbytesAvailable=inputStream.available();
intbufferSize=Math.min(bytesAvailable,maxBufferSize);
finalbyte[]buffers=newbyte[bufferSize];
while((read=inputStream.read(buffers))!=-1){
outputStream.write(buffers,0,read);
}
returnCursor.close();
inputStream.close();
outputStream.close();
returnfile.getPath();
}catch(Exceptione){
e.printStackTrace();
}
returnnull;
}

附上全系统的代码:

/**
*文件Uri转路径(兼容各品牌手机)
*/
publicclassPathUtils{
/**
*android7.0以上处理方法
*/
privatestaticStringgetFilePathForN(Contextcontext,Uriuri){
try{
CursorreturnCursor=context.getContentResolver().query(uri,null,null,null,null);
intnameIndex=returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
returnCursor.moveToFirst();
Stringname=(returnCursor.getString(nameIndex));
Filefile=newFile(context.getFilesDir(),name);
InputStreaminputStream=context.getContentResolver().openInputStream(uri);
FileOutputStreamoutputStream=newFileOutputStream(file);
intread=0;
intmaxBufferSize=1*1024*1024;
intbytesAvailable=inputStream.available();

intbufferSize=Math.min(bytesAvailable,maxBufferSize);

finalbyte[]buffers=newbyte[bufferSize];
while((read=inputStream.read(buffers))!=-1){
outputStream.write(buffers,0,read);
}
returnCursor.close();
inputStream.close();
outputStream.close();
returnfile.getPath();
}catch(Exceptione){
e.printStackTrace();
}
returnnull;
}

/**
*全平台处理方法
*/
publicstaticStringgetPath(finalContextcontext,finalUriuri)throwsException{

finalbooleanisKitKat=Build.VERSION.SDK_INT>=Build.VERSION_CODES.KITKAT;
finalbooleanisN=Build.VERSION.SDK_INT>=Build.VERSION_CODES.N;

if(isN){
returngetFilePathForN(context,uri);
}

//DocumentProvider
if(isKitKat&&DocumentsContract.isDocumentUri(context,uri)){
//ExternalStorageProvider
if(isExternalStorageDocument(uri)){
finalStringdocId=DocumentsContract.getDocumentId(uri);
finalString[]split=docId.split(":");
finalStringtype=split[0];

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

}
//DownloadsProvider
elseif(isDownloadsDocument(uri)){

finalStringid=DocumentsContract.getDocumentId(uri);
finalUricontentUri=ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"),StringUtils.toLong(id));

returngetDataColumn(context,contentUri,null,null);
}
//MediaProvider
elseif(isMediaDocument(uri)){
finalStringdocId=DocumentsContract.getDocumentId(uri);
finalString[]split=docId.split(":");
finalStringtype=split[0];

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

finalStringselection="_id=?";
finalString[]selectionArgs=newString[]{
split[1]
};

returngetDataColumn(context,contentUri,selection,selectionArgs);
}
}
//MediaStore(andgeneral)
elseif("content".equalsIgnoreCase(uri.getScheme())){
returngetDataColumn(context,uri,null,null);
}
//File
elseif("file".equalsIgnoreCase(uri.getScheme())){
returnuri.getPath();
}

returnnull;
}

/**
*获取此Uri的数据列的值。这对于MediaStoreuri和其他基于文件的内容提供程序非常有用。
*/
publicstaticStringgetDataColumn(Contextcontext,Uriuri,Stringselection,
String[]selectionArgs){

Cursorcursor=null;
finalStringcolumn="_data";
finalString[]projection={
column
};

try{
cursor=context.getContentResolver().query(uri,projection,selection,selectionArgs,
null);
if(cursor!=null&&cursor.moveToFirst()){
finalintcolumn_index=cursor.getColumnIndexOrThrow(column);
returncursor.getString(column_index);
}
}catch(IllegalArgumentExceptione){
//donothing
}finally{
if(cursor!=null)
cursor.close();
}
returnnull;
}

publicstaticbooleanisExternalStorageDocument(Uriuri){
return"com.android.externalstorage.documents".equals(uri.getAuthority());
}

publicstaticbooleanisDownloadsDocument(Uriuri){
return"com.android.providers.downloads.documents".equals(uri.getAuthority());
}

publicstaticbooleanisMediaDocument(Uriuri){
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以上的标准的解析,然后失败了,并非不回调。

直接可用的代码片段:

publicclassFileUtils{

privateContextcontext;

publicFileUtils(Contextcontext){
this.context=context;
}

publicStringgetFilePathByUri(Uriuri){
//以file://开头的
if(ContentResolver.SCHEME_FILE.equals(uri.getScheme())){
returnuri.getPath();
}
//以/storage开头的也直接返回
if(isOtherDocument(uri)){
returnuri.getPath();
}
//版本兼容的获取!
Stringpath=getFilePathByUri_BELOWAPI11(uri);
if(path!=null){
LogUtils.d("getFilePathByUri_BELOWAPI11获取到的路径为:"+path);
returnpath;
}
path=getFilePathByUri_API11to18(uri);
if(path!=null){
LogUtils.d("getFilePathByUri_API11to18获取到的路径为:"+path);
returnpath;
}
path=getFilePathByUri_API19(uri);
LogUtils.d("getFilePathByUri_API19获取到的路径为:"+path);
returnpath;
}

privateStringgetFilePathByUri_BELOWAPI11(Uriuri){
//以content://开头的,比如content://media/extenral/images/media/17766
if(ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())){
Stringpath=null;
String[]projection=newString[]{MediaStore.Images.Media.DATA};
Cursorcursor=context.getContentResolver().query(uri,projection,null,null,null);
if(cursor!=null){
if(cursor.moveToFirst()){
intcolumnIndex=cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
if(columnIndex>-1){
path=cursor.getString(columnIndex);
}
}
cursor.close();
}
returnpath;
}
returnnull;
}

privateStringgetFilePathByUri_API11to18(UricontentUri){
String[]projection={MediaStore.Images.Media.DATA};
Stringresult=null;
CursorLoadercursorLoader=newCursorLoader(context,contentUri,projection,null,null,null);
Cursorcursor=cursorLoader.loadInBackground();
if(cursor!=null){
intcolumn_index=cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
result=cursor.getString(column_index);
cursor.close();
}
returnresult;
}

privateStringgetFilePathByUri_API19(Uriuri){
//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
StringdocId=DocumentsContract.getDocumentId(uri);
String[]split=docId.split(":");
Stringtype=split[0];
if("primary".equalsIgnoreCase(type)){
if(split.length>1){
returnEnvironment.getExternalStorageDirectory()+"/"+split[1];
}else{
returnEnvironment.getExternalStorageDirectory()+"/";
}
//ThisisforcheckingSDCard
}
}elseif(isDownloadsDocument(uri)){
//下载内容提供者时应当判断下载管理器是否被禁用
intstateCode=context.getPackageManager().getApplicationEnabledSetting("com.android.providers.downloads");
if(stateCode!=0&&stateCode!=1){
returnnull;
}
Stringid=DocumentsContract.getDocumentId(uri);
//如果出现这个RAW地址,我们则可以直接返回!
if(id.startsWith("raw:")){
returnid.replaceFirst("raw:","");
}
if(id.contains(":")){
String[]tmp=id.split(":");
if(tmp.length>1){
id=tmp[1];
}
}
UricontentUri=Uri.parse("content://downloads/public_downloads");
LogUtils.d("测试打印Uri:"+uri);
try{
contentUri=ContentUris.withAppendedId(contentUri,Long.parseLong(id));
}catch(Exceptione){
e.printStackTrace();
}
Stringpath=getDataColumn(contentUri,null,null);
if(path!=null)returnpath;
//兼容某些特殊情况下的文件管理器!
StringfileName=getFileNameByUri(uri);
if(fileName!=null){
path=Environment.getExternalStorageDirectory().toString()+"/Download/"+fileName;
returnpath;
}
}elseif(isMediaDocument(uri)){
//MediaProvider
StringdocId=DocumentsContract.getDocumentId(uri);
String[]split=docId.split(":");
Stringtype=split[0];
UricontentUri=null;
if("image".equals(type)){
contentUri=MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
}elseif("video".equals(type)){
contentUri=MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
}elseif("audio".equals(type)){
contentUri=MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
Stringselection="_id=?";
String[]selectionArgs=newString[]{split[1]};
returngetDataColumn(contentUri,selection,selectionArgs);
}
}
}
returnnull;
}

privateStringgetFileNameByUri(Uriuri){
StringrelativePath=getFileRelativePathByUri_API18(uri);
if(relativePath==null)relativePath="";
finalString[]projection={
MediaStore.MediaColumns.DISPLAY_NAME
};
try(Cursorcursor=context.getContentResolver().query(uri,projection,null,null,null)){
if(cursor!=null&&cursor.moveToFirst()){
intindex=cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME);
returnrelativePath+cursor.getString(index);
}
}
returnnull;
}

privateStringgetFileRelativePathByUri_API18(Uriuri){
finalString[]projection;
if(android.os.Build.VERSION.SDK_INT>=android.os.Build.VERSION_CODES.Q){
projection=newString[]{
MediaStore.MediaColumns.RELATIVE_PATH
};
try(Cursorcursor=context.getContentResolver().query(uri,projection,null,null,null)){
if(cursor!=null&&cursor.moveToFirst()){
intindex=cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.RELATIVE_PATH);
returncursor.getString(index);
}
}
}
returnnull;
}

privateStringgetDataColumn(Uriuri,Stringselection,String[]selectionArgs){
finalStringcolumn=MediaStore.Images.Media.DATA;
finalString[]projection={column};
try(Cursorcursor=context.getContentResolver().query(uri,projection,selection,selectionArgs,null)){
if(cursor!=null&&cursor.moveToFirst()){
finalintcolumn_index=cursor.getColumnIndexOrThrow(column);
returncursor.getString(column_index);
}
}catch(IllegalArgumentExceptioniae){
iae.printStackTrace();
}
returnnull;
}

privatebooleanisExternalStorageDocument(Uriuri){
return"com.android.externalstorage.documents".equals(uri.getAuthority());
}

privatebooleanisOtherDocument(Uriuri){
//以/storage开头的也直接返回
if(uri!=null&&uri.getPath()!=null){
Stringpath=uri.getPath();
if(path.startsWith("/storage")){
returntrue;
}
if(path.startsWith("/external_files")){
returntrue;
}
}
returnfalse;
}

privatebooleanisDownloadsDocument(Uriuri){
return"com.android.providers.downloads.documents".equals(uri.getAuthority());
}

privatebooleanisMediaDocument(Uriuri){
return"com.android.providers.media.documents".equals(uri.getAuthority());
}
}

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

感谢各位的阅读!关于“Android7.0以上如何实现Uri转路径”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

发布于 2021-05-10 20:36:40
收藏
分享
海报
0 条评论
167
上一篇:Android Studio怎么设置代码提示和代码自动补全快捷键方式 下一篇:Android studio3.6中JNI教程之helloworld的思路分析
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码