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
另发现一篇,亲测,Android4.4到Android10可用,测试的系统有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(Uriuri)即可获得最终的路径。
到此这篇关于Android7.0以上Uri转路径的方法实现(已验证)的文章就介绍到这了,更多相关Android7Uri转路径内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。