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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。