一、前言
Android 4.4(API级别19)引入了存储访问框架(SAF)。
通过SAF,用户可以轻松地浏览和打开所有首选文档存储提供商中的文档,图像和其他文件。
也就是说,接下来介绍的方式适用于android4.4+的操作系统。
参考链接:https://developer.android.com/guide/topics/providers/document-provider
二、详细实现
1、调出系统文件管理器界面
private static final int READ_REQUEST_CODE = 42;
...
/*** Fires an intent to spin up the "file chooser" UI and select an image.*/
public void performFileSearch() {// ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's file// browser.Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);// Filter to only show results that can be "opened", such as a// file (as opposed to a list of contacts or timezones)intent.addCategory(Intent.CATEGORY_OPENABLE);// Filter to show only images, using the image MIME data type.// If one wanted to search for ogg vorbis files, the type would be "audio/ogg".// To search for all documents available via installed storage providers,// it would be "*/*".intent.setType("image/*");startActivityForResult(intent, READ_REQUEST_CODE);
}
1)Intent除了可以设置为ACTION_OPEN_DOCUMEN
,还可以替换为ACTION_GET_CONTENT
,两者的区别如下:
- 如果您希望您的应用
仅读取/导入数据
,请使用ACTION_GET_CONTENT
。 通过这种方法,应用程序可以导入数据的副本
,例如图像文件。 - 如果希望您的应用对文件提供者拥有的文件
具有长期,持久的访问权限
,请使用ACTION_OPEN_DOCUMENT
。
2)Category设置为CATEGORY_OPENABLE
,过滤出可以打开的文件
3)Type设置的是MIMETYPE,比如:
- 过滤所有图片,则设置为:
"image/*"
- 只过滤png图片,则设置为:
"image/png"
- 过滤apk,那么可设置为:
"application/vnd.android.package-archive"
4)startActivityForResult
启动Inetent,以便在onActivityResult
接收文件选择结果
2、在onActivityResult中处理返回结果
@Override
public void onActivityResult(int requestCode, int resultCode,Intent resultData) {// The ACTION_OPEN_DOCUMENT intent was sent with the request code// READ_REQUEST_CODE. If the request code seen here doesn't match, it's the// response to some other intent, and the code below shouldn't run at all.if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {// The document selected by the user won't be returned in the intent.// Instead, a URI to that document will be contained in the return intent// provided to this method as a parameter.// Pull that URI using resultData.getData().Uri uri = null;if (resultData != null) {uri = resultData.getData();Log.i(TAG, "Uri: " + uri.toString());showImage(uri);}}
}
1)从Intent中getData()获取到返回的Uri对象,旧版本是file://开头,新版本是content://开头
3、从Uri获取所需的信息
1)从Uri中获取文件元数据,一般只能获取到文件名与大小
public void dumpImageMetaData(Uri uri) {// The query, since it only applies to a single document, will only return// one row. There's no need to filter, sort, or select fields, since we want// all fields for one document.Cursor cursor = getActivity().getContentResolver().query(uri, null, null, null, null, null);try {// moveToFirst() returns false if the cursor has 0 rows. Very handy for// "if there's anything to look at, look at it" conditionals.if (cursor != null && cursor.moveToFirst()) {// Note it's called "Display Name". This is// provider-specific, and might not necessarily be the file name.String displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));Log.i(TAG, "Display Name: " + displayName);int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);// If the size is unknown, the value stored is null. But since an// int can't be null in Java, the behavior is implementation-specific,// which is just a fancy term for "unpredictable". So as// a rule, check if it's null before assigning to an int. This will// happen often: The storage API allows for remote files, whose// size might not be locally known.String size = null;if (!cursor.isNull(sizeIndex)) {// Technically the column stores an int, but cursor.getString()// will do the conversion automatically.size = cursor.getString(sizeIndex);} else {size = "Unknown";}Log.i(TAG, "Size: " + size);}} finally {cursor.close();}
}
2)将Uri转换为Bitmap
private Bitmap getBitmapFromUri(Uri uri) throws IOException {ParcelFileDescriptor parcelFileDescriptor =getContentResolver().openFileDescriptor(uri, "r");FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);parcelFileDescriptor.close();return image;
}
3)将Uri转换为InputStream
private String readTextFromUri(Uri uri) throws IOException {StringBuilder stringBuilder = new StringBuilder();try (InputStream inputStream =getContentResolver().openInputStream(uri);BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(inputStream)))) {String line;while ((line = reader.readLine()) != null) {stringBuilder.append(line);}}return stringBuilder.toString();
}
MIMETYPE 常见的用法:
文件类型 | mime名称 | 文件类型 | mime名称 |
---|---|---|---|
3gp | video/3gpp | pdb | chemical/x-pdb |
aab | application/x-authoware-bin | application/pdf | |
aam | application/x-authoware-map | pfr | application/font-tdpfr |
aas | application/x-authoware-seg | pgm | image/x-portable-graymap |
ai | application/postscript | pict | image/x-pict |
aif | audio/x-aiff | pm | application/x-perl |
aifc | audio/x-aiff | pmd | application/x-pmd |
aiff | audio/x-aiff | png | image/png |
als | audio/X-Alpha5 | pnm | image/x-portable-anymap |
amc | application/x-mpeg | pnz | image/png |
ani | application/octet-stream | pot | application/vnd.ms-powerpoint |
apk | application/vnd.android.package-archive | ppm | image/x-portable-pixmap |
asc | text/plain | pps | application/vnd.ms-powerpoint |
asd | application/astound | ppt | application/vnd.ms-powerpoint |
asf | video/x-ms-asf | pqf | application/x-cprplayer |
asn | application/astound | pqi | application/cprplayer |
asp | application/x-asap | prc | application/x-prc |
asx | video/x-ms-asf | proxy | application/x-ns-proxy-autoconfig |
au | audio/basic | ps | application/postscript |
avb | application/octet-stream | ptlk | application/listenup |
avi | video/x-msvideo | pub | application/x-mspublisher |
awb | audio/amr-wb | pvx | video/x-pv-pvx |
bcpio | application/x-bcpio | qcp | audio/vnd.qcelp |
bin | application/octet-stream | qt | video/quicktime |
bld | application/bld | qti | image/x-quicktime |
bld2 | application/bld2 | qtif | image/x-quicktime |
bmp | image/bmp | r3t | text/vnd.rn-realtext3d |
bpk | application/octet-stream | ra | audio/x-pn-realaudio |
bz2 | application/x-bzip2 | ram | audio/x-pn-realaudio |
cal | image/x-cals | rar | application/x-rar-compressed |
ccn | application/x-cnc | ras | image/x-cmu-raster |
cco | application/x-cocoa | rdf | application/rdf+xml |
cdf | application/x-netcdf | rf | image/vnd.rn-realflash |
cgi | magnus-internal/cgi | rgb | image/x-rgb |
chat | application/x-chat | rlf | application/x-richlink |
class | application/octet-stream | rm | audio/x-pn-realaudio |
clp | application/x-msclip | rmf | audio/x-rmf |
cmx | application/x-cmx | rmm | audio/x-pn-realaudio |
co | application/x-cult3d-object | rmvb | audio/x-pn-realaudio |
cod | image/cis-cod | rnx | application/vnd.rn-realplayer |
cpio | application/x-cpio | roff | application/x-troff |
cpt | application/mac-compactpro | rp | image/vnd.rn-realpix |
crd | application/x-mscardfile | rpm | audio/x-pn-realaudio-plugin |
csh | application/x-csh | rt | text/vnd.rn-realtext |
csm | chemical/x-csml | rte | x-lml/x-gps |
csml | chemical/x-csml | rtf | application/rtf |
css | text/css | rtg | application/metastream |
cur | application/octet-stream | rtx | text/richtext |
dcm | x-lml/x-evm | rv | video/vnd.rn-realvideo |
dcr | application/x-director | rwc | application/x-rogerwilco |
dcx | image/x-dcx | s3m | audio/x-mod |
dhtml | text/html | s3z | audio/x-mod |
dir | application/x-director | sca | application/x-supercard |
dll | application/octet-stream | scd | application/x-msschedule |
dmg | application/octet-stream | sdf | application/e-score |
dms | application/octet-stream | sea | application/x-stuffit |
doc | application/msword | sgm | text/x-sgml |
dot | application/x-dot | sgml | text/x-sgml |
dvi | application/x-dvi | sh | application/x-sh |
dwf | drawing/x-dwf | shar | application/x-shar |
dwg | application/x-autocad | shtml | magnus-internal/parsed-html |
dxf | application/x-autocad | shw | application/presentations |
dxr | application/x-director | si6 | image/si6 |
ebk | application/x-expandedbook | si7 | image/vnd.stiwap.sis |
emb | chemical/x-embl-dl-nucleotide | si9 | image/vnd.lgtwap.sis |
embl | chemical/x-embl-dl-nucleotide | sis | application/vnd.symbian.install |
eps | application/postscript | sit | application/x-stuffit |
eri | image/x-eri | skd | application/x-Koan |
es | audio/echospeech | skm | application/x-Koan |
esl | audio/echospeech | skp | application/x-Koan |
etc | application/x-earthtime | skt | application/x-Koan |
etx | text/x-setext | slc | application/x-salsa |
evm | x-lml/x-evm | smd | audio/x-smd |
evy | application/x-envoy | smi | application/smil |
exe | application/octet-stream | smil | application/smil |
fh4 | image/x-freehand | smp | application/studiom |
fh5 | image/x-freehand | smz | audio/x-smd |
fhc | image/x-freehand | snd | audio/basic |
fif | image/fif | spc | text/x-speech |
fm | application/x-maker | spl | application/futuresplash |
fpx | image/x-fpx | spr | application/x-sprite |
fvi | video/isivideo | sprite | application/x-sprite |
gau | chemical/x-gaussian-input | spt | application/x-spt |
gca | application/x-gca-compressed | src | application/x-wais-source |
gdb | x-lml/x-gdb | stk | application/hyperstudio |
gif | image/gif | stm | audio/x-mod |
gps | application/x-gps | sv4cpio | application/x-sv4cpio |
gtar | application/x-gtar | sv4crc | application/x-sv4crc |
gz | application/x-gzip | svf | image/vnd |
hdf | application/x-hdf | svg | image/svg-xml |
hdm | text/x-hdml | svh | image/svh |
hdml | text/x-hdml | svr | x-world/x-svr |
hlp | application/winhlp | swf | application/x-shockwave-flash |
hqx | application/mac-binhex40 | swfl | application/x-shockwave-flash |
htm | text/html | t | application/x-troff |
html | text/html | tad | application/octet-stream |
hts | text/html | talk | text/x-speech |
ice | x-conference/x-cooltalk | tar | application/x-tar |
ico | application/octet-stream | taz | application/x-tar |
ief | image/ief | tbp | application/x-timbuktu |
ifm | image/gif | tbt | application/x-timbuktu |
ifs | image/ifs | tcl | application/x-tcl |
imy | audio/melody | tex | application/x-tex |
ins | application/x-NET-Install | texi | application/x-texinfo |
ips | application/x-ipscript | texinfo | application/x-texinfo |
ipx | application/x-ipix | tgz | application/x-tar |
it | audio/x-mod | thm | application/vnd.eri.thm |
itz | audio/x-mod | tif | image/tiff |
ivr | i-world/i-vrml | tiff | image/tiff |
j2k | image/j2k | tki | application/x-tkined |
jad | text/vnd.sun.j2me.app-descriptor | tkined | application/x-tkined |
jam | application/x-jam | toc | application/toc |
jar | application/java-archive | toy | image/toy |
jnlp | application/x-java-jnlp-file | tr | application/x-troff |
jpe | image/jpeg | trk | x-lml/x-gps |
jpeg | image/jpeg | trm | application/x-msterminal |
jpg | image/jpeg | tsi | audio/tsplayer |
jpz | image/jpeg | tsp | application/dsptype |
js | application/x-javascript | tsv | text/tab-separated-values |
jwc | application/jwc | tsv | text/tab-separated-values |
kjx | application/x-kjx | ttf | application/octet-stream |
lak | x-lml/x-lak | ttz | application/t-time |
latex | application/x-latex | txt | text/plain |
lcc | application/fastman | ult | audio/x-mod |
lcl | application/x-digitalloca | ustar | application/x-ustar |
lcr | application/x-digitalloca | uu | application/x-uuencode |
lgh | application/lgh | uue | application/x-uuencode |
lha | application/octet-stream | vcd | application/x-cdlink |
lml | x-lml/x-lml | vcf | text/x-vcard |
lmlpack | x-lml/x-lmlpack | vdo | video/vdo |
lsf | video/x-ms-asf | vib | audio/vib |
lsx | video/x-ms-asf | viv | video/vivo |
lzh | application/x-lzh | vivo | video/vivo |
m13 | application/x-msmediaview | vmd | application/vocaltec-media-desc |
m14 | application/x-msmediaview | vmf | application/vocaltec-media-file |
m15 | audio/x-mod | vmi | application/x-dreamcast-vms-info |
m3u | audio/x-mpegurl | vms | application/x-dreamcast-vms |
m3url | audio/x-mpegurl | vox | audio/voxware |
ma1 | audio/ma1 | vqe | audio/x-twinvq-plugin |
ma2 | audio/ma2 | vqf | audio/x-twinvq |
ma3 | audio/ma3 | vql | audio/x-twinvq |
ma5 | audio/ma5 | vre | x-world/x-vream |
man | application/x-troff-man | vrml | x-world/x-vrml |
map | magnus-internal/imagemap | vrt | x-world/x-vrt |
mbd | application/mbedlet | vrw | x-world/x-vream |
mct | application/x-mascot | vts | workbook/formulaone |
mdb | application/x-msaccess | wav | audio/x-wav |
mdz | audio/x-mod | wax | audio/x-ms-wax |
me | application/x-troff-me | wbmp | image/vnd.wap.wbmp |
mel | text/x-vmel | web | application/vnd.xara |
mi | application/x-mif | wi | image/wavelet |
mid | audio/midi | wis | application/x-InstallShield |
midi | audio/midi | wm | video/x-ms-wm |
mif | application/x-mif | wma | audio/x-ms-wma |
mil | image/x-cals | wmd | application/x-ms-wmd |
mio | audio/x-mio | wmf | application/x-msmetafile |
mmf | application/x-skt-lbs | wml | text/vnd.wap.wml |
mng | video/x-mng | wmlc | application/vnd.wap.wmlc |
mny | application/x-msmoney | wmls | text/vnd.wap.wmlscript |
moc | application/x-mocha | wmlsc | application/vnd.wap.wmlscriptc |
mocha | application/x-mocha | wmlscript | text/vnd.wap.wmlscript |
mod | audio/x-mod | wmv | audio/x-ms-wmv |
mof | application/x-yumekara | wmx | video/x-ms-wmx |
mol | chemical/x-mdl-molfile | wmz | application/x-ms-wmz |
mop | chemical/x-mopac-input | wpng | image/x-up-wpng |
mov | video/quicktime | wpt | x-lml/x-gps |
movie | video/x-sgi-movie | wri | application/x-mswrite |
mp2 | audio/x-mpeg | wrl | x-world/x-vrml |
mp3 | audio/x-mpeg | wrz | x-world/x-vrml |
mp4 | video/mp4 | ws | text/vnd.wap.wmlscript |
mpc | application/vnd.mpohun.certificate | wsc | application/vnd.wap.wmlscriptc |
mpe | video/mpeg | wv | video/wavelet |
mpeg | video/mpeg | wvx | video/x-ms-wvx |
mpg | video/mpeg | wxl | application/x-wxl |
mpg4 | video/mp4 | x-gzip | application/x-gzip |
mpga | audio/mpeg | xar | application/vnd.xara |
mpn | application/vnd.mophun.application | xbm | image/x-xbitmap |
mpp | application/vnd.ms-project | xdm | application/x-xdma |
mps | application/x-mapserver | xdma | application/x-xdma |
mrl | text/x-mrml | xdw | application/vnd.fujixerox.docuworks |
mrm | application/x-mrm | xht | application/xhtml+xml |
ms | application/x-troff-ms | xhtm | application/xhtml+xml |
mts | application/metastream | xhtml | application/xhtml+xml |
mtx | application/metastream | xla | application/vnd.ms-excel |
mtz | application/metastream | xlc | application/vnd.ms-excel |
mzv | application/metastream | xll | application/x-excel |
nar | application/zip | xlm | application/vnd.ms-excel |
nbmp | image/nbmp | xls | application/vnd.ms-excel |
nc | application/x-netcdf | xlt | application/vnd.ms-excel |
ndb | x-lml/x-ndb | xlw | application/vnd.ms-excel |
ndwn | application/ndwn | xm | audio/x-mod |
nif | application/x-nif | xml | text/xml |
nmz | application/x-scream | xmz | audio/x-mod |
nokia-op-logo | image/vnd.nok-oplogo-color | xpi | application/x-xpinstall |
npx | application/x-netfpx | xpm | image/x-xpixmap |
nsnd | audio/nsnd | xsit | text/xml |
nva | application/x-neva1 | xsl | text/xml |
oda | application/oda | xul | text/xul |
oom | application/x-AtlasMate-Plugin | xwd | image/x-xwindowdump |
pac | audio/x-pac | xyz | chemical/x-pdb |
pae | audio/x-epac | yz1 | application/x-yz1 |
pan | application/x-pan | z | application/x-compress |
pbm | image/x-portable-bitmap | zac | application/x-zaurus-zac |
pcx | image/x-pcx | zip | application/zip |
三、文件创建、编辑与删除
1、创建文件,可以在onActivity中接收到结果
// Here are some examples of how you might call this method.
// The first parameter is the MIME type, and the second parameter is the name
// of the file you are creating:
//
// createFile("text/plain", "foobar.txt");
// createFile("image/png", "mypicture.png");// Unique request code.
private static final int WRITE_REQUEST_CODE = 43;
...
private void createFile(String mimeType, String fileName) {Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);// Filter to only show results that can be "opened", such as// a file (as opposed to a list of contacts or timezones).intent.addCategory(Intent.CATEGORY_OPENABLE);// Create a file with the requested MIME type.intent.setType(mimeType);intent.putExtra(Intent.EXTRA_TITLE, fileName);startActivityForResult(intent, WRITE_REQUEST_CODE);
}
2、获取Uri之后,要是文件的Document.COLUMN_FLAGS
包含SUPPORTS_DELETE
,则可以删除该文件:
DocumentsContract.deleteDocument(getContentResolver(), uri);
3、编辑文件
private static final int EDIT_REQUEST_CODE = 44;
/*** Open a file for writing and append some text to it.*/private void editDocument() {// ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's// file browser.Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);// Filter to only show results that can be "opened", such as a// file (as opposed to a list of contacts or timezones).intent.addCategory(Intent.CATEGORY_OPENABLE);// Filter to show only text files.intent.setType("text/plain");startActivityForResult(intent, EDIT_REQUEST_CODE);
}private void alterDocument(Uri uri) {try {ParcelFileDescriptor pfd = getActivity().getContentResolver().openFileDescriptor(uri, "w");FileOutputStream fileOutputStream =new FileOutputStream(pfd.getFileDescriptor());fileOutputStream.write(("Overwritten by MyCloud at " +System.currentTimeMillis() + "\n").getBytes());// Let the document provider know you're done by closing the stream.fileOutputStream.close();pfd.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}
}
4、检查最新的文件数据
final int takeFlags = intent.getFlags()& (Intent.FLAG_GRANT_READ_URI_PERMISSION| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// Check for the freshest data.
getContentResolver().takePersistableUriPermission(uri, takeFlags);
四、拓展
1、Android 7.0
在存储访问框架中添加了虚拟文件
的概念。
2、即使虚拟文件没有二进制
表示形式,您的客户端应用程序也可以通过将其强制转换为其他文件类型或使用ACTION_VIEW意图查看这些文件来打开其内容
。
3、要打开虚拟文件,您的客户端应用程序需要包含特殊的逻辑来处理它们。如果要获取文件的字节表示形式(例如,预览文件),则需要从文档提供者处请求其他MIME类型。
4、要在您的应用程序中获取虚拟文档的URI,首先要创建一个Intent以打开文件选择器UI
,就像前面在Seach中为文档显示的代码一样。
5、重要提示:由于应用无法使用openInputStream()方法直接打开虚拟文件
,因此,如果您在ACTION_OPEN_DOCUMENT意向中包括CATEGORY_OPENABLE类别,则您的应用将不会收到任何虚拟文件。用户做出选择后,系统将调用onActivityResult()方法,如先前在处理结果中所示。您的应用可以检索文件的URI,然后使用类似于以下代码片段的方法来确定文件是否为虚拟文件。验证文件为虚拟文件后,可以将其强制转换为其他MIME类型
,例如图像文件。以下代码段显示了如何检查虚拟文件是否可以表示为映像,如果可以,则从虚拟文件获取输入流。
private boolean isVirtualFile(Uri uri) {if (!DocumentsContract.isDocumentUri(this, uri)) {return false;}Cursor cursor = getContentResolver().query(uri,new String[] { DocumentsContract.Document.COLUMN_FLAGS },null, null, null);int flags = 0;if (cursor.moveToFirst()) {flags = cursor.getInt(0);}cursor.close();return (flags & DocumentsContract.Document.FLAG_VIRTUAL_DOCUMENT) != 0;
}private InputStream getInputStreamForVirtualFile(Uri uri, String mimeTypeFilter)throws IOException {ContentResolver resolver = getContentResolver();String[] openableMimeTypes = resolver.getStreamTypes(uri, mimeTypeFilter);if (openableMimeTypes == null ||openableMimeTypes.length < 1) {throw new FileNotFoundException();}return resolver.openTypedAssetFileDescriptor(uri, openableMimeTypes[0], null).createInputStream();
}