Android打开系统文件管理器

一、前言

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 pdf 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();
}

你可能感兴趣的:(android)