转载来源:https://blog.csdn.net/qq_27061049/article/details/94178875

1.相关方法说明:

Android判断有无外置SD卡(TF卡),并读写文件_第1张图片

2.Android Manifest.xml 添加权限

   
   
   
   

 3.DocumentsUtils文件

import android.annotation.TargetApi;import android.content.Context;import android.content.SharedPreferences;import android.net.Uri;import android.os.Build;import android.preference.PreferenceManager;import android.provider.DocumentsContract;import android.support.v4.provider.DocumentFile;import android.util.Log;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.util.ArrayList;import java.util.List; public class DocumentsUtils {    private static final String TAG = DocumentsUtils.class.getSimpleName();    public static final int OPEN_DOCUMENT_TREE_CODE = 8000;    private static List sExtSdCardPaths = new ArrayList<>();    private DocumentsUtils() {    }    public static void cleanCache() {        sExtSdCardPaths.clear();    }    /**     * Get a list of external SD card paths. (Kitkat or higher.)     *     * @return A list of external SD card paths.     */    @TargetApi(Build.VERSION_CODES.KITKAT)    private static String[] getExtSdCardPaths(Context context) {        if (sExtSdCardPaths.size() > 0) {            return sExtSdCardPaths.toArray(new String[0]);        }        for (File file : context.getExternalFilesDirs("external")) {            if (file != null && !file.equals(context.getExternalFilesDir("external"))) {                int index = file.getAbsolutePath().lastIndexOf("/Android/data");                if (index < 0) {                    Log.w(TAG, "Unexpected external file dir: " + file.getAbsolutePath());                } else {                    String path = file.getAbsolutePath().substring(0, index);                    try {                        path = new File(path).getCanonicalPath();                    } catch (IOException e) {                        // Keep non-canonical path.                    }                    sExtSdCardPaths.add(path);                }            }        }        if (sExtSdCardPaths.isEmpty()) sExtSdCardPaths.add("/storage/sdcard1");        return sExtSdCardPaths.toArray(new String[0]);    }    /**     * Determine the main folder of the external SD card containing the given file.     *     * @param file the file.     * @return The main folder of the external SD card containing this file, if the file is on an SD     * card. Otherwise,     * null is returned.     */    @TargetApi(Build.VERSION_CODES.KITKAT)    private static String getExtSdCardFolder(final File file, Context context) {        String[] extSdPaths = getExtSdCardPaths(context);        try {            for (int i = 0; i < extSdPaths.length; i++) {                if (file.getCanonicalPath().startsWith(extSdPaths[i])) {                    return extSdPaths[i];                }            }        } catch (IOException e) {            return null;        }        return null;    }    /**     * Determine if a file is on external sd card. (Kitkat or higher.)     *     * @param file The file.     * @return true if on external sd card.     */    @TargetApi(Build.VERSION_CODES.KITKAT)    public static boolean isOnExtSdCard(final File file, Context c) {        return getExtSdCardFolder(file, c) != null;    }    /**     * Get a DocumentFile corresponding to the given file (for writing on ExtSdCard on Android 5).     * If the file is not     * existing, it is created.     *     * @param file        The file.     * @param isDirectory flag indicating if the file should be a directory.     * @return The DocumentFile     */    public static DocumentFile getDocumentFile(final File file, final boolean isDirectory,                                               Context context) {        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {            return DocumentFile.fromFile(file);        }        String baseFolder = getExtSdCardFolder(file, context);        Log.i(TAG,"lum_ baseFolder " + baseFolder);        boolean originalDirectory = false;        if (baseFolder == null) {            return null;        }        String relativePath = null;        try {            String fullPath = file.getCanonicalPath();            if (!baseFolder.equals(fullPath)) {                relativePath = fullPath.substring(baseFolder.length() + 1);            } else {                originalDirectory = true;            }        } catch (IOException e) {            return null;        } catch (Exception f) {            originalDirectory = true;            //continue        }        String as = PreferenceManager.getDefaultSharedPreferences(context).getString(baseFolder,                null);        Uri treeUri = null;        if (as != null) treeUri = Uri.parse(as);        if (treeUri == null) {            return null;        }        // start with root of SD card and then parse through document tree.        DocumentFile document = DocumentFile.fromTreeUri(context, treeUri);        if (originalDirectory) return document;        String[] parts = relativePath.split("/");        for (int i = 0; i < parts.length; i++) {            DocumentFile nextDocument = document.findFile(parts[i]);            if (nextDocument == null) {                if ((i < parts.length - 1) || isDirectory) {                    nextDocument = document.createDirectory(parts[i]);                } else {                    nextDocument = document.createFile("image", parts[i]);                }            }            document = nextDocument;        }        return document;    }    public static boolean mkdirs(Context context, File dir) {        boolean res = dir.mkdirs();        if (!res) {            if (DocumentsUtils.isOnExtSdCard(dir, context)) {                DocumentFile documentFile = DocumentsUtils.getDocumentFile(dir, true, context);                res = documentFile != null && documentFile.canWrite();            }        }        return res;    }    public static boolean delete(Context context, File file) {        boolean ret = file.delete();        if (!ret && DocumentsUtils.isOnExtSdCard(file, context)) {            DocumentFile f = DocumentsUtils.getDocumentFile(file, false, context);            if (f != null) {                ret = f.delete();            }        }        return ret;    }    public static boolean canWrite(File file) {        boolean res = file.exists() && file.canWrite();        if (!res && !file.exists()) {            try {                if (!file.isDirectory()) {                    res = file.createNewFile() && file.delete();                } else {                    res = file.mkdirs() && file.delete();                }            } catch (IOException e) {                e.printStackTrace();            }        }        return res;    }    public static boolean canWrite(Context context, File file) {        boolean res = canWrite(file);        if (!res && DocumentsUtils.isOnExtSdCard(file, context)) {            DocumentFile documentFile = DocumentsUtils.getDocumentFile(file, true, context);            res = documentFile != null && documentFile.canWrite();        }        return res;    }    public static boolean renameTo(Context context, File src, File dest) {        boolean res = src.renameTo(dest);        if (!res && isOnExtSdCard(dest, context)) {            DocumentFile srcDoc;            if (isOnExtSdCard(src, context)) {                srcDoc = getDocumentFile(src, false, context);            } else {                srcDoc = DocumentFile.fromFile(src);            }            DocumentFile destDoc = getDocumentFile(dest.getParentFile(), true, context);            if (srcDoc != null && destDoc != null) {                try {                    if (src.getParent().equals(dest.getParent())) {                        res = srcDoc.renameTo(dest.getName());                    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {                        res = DocumentsContract.moveDocument(context.getContentResolver(),                                srcDoc.getUri(),                                srcDoc.getParentFile().getUri(),                                destDoc.getUri()) != null;                    }                } catch (Exception e) {                    e.printStackTrace();                }            }        }        return res;    }    public static InputStream getInputStream(Context context, File destFile) {        InputStream in = null;        try {            if (!canWrite(destFile) && isOnExtSdCard(destFile, context)) {                DocumentFile file = DocumentsUtils.getDocumentFile(destFile, false, context);                if (file != null && file.canWrite()) {                    in = context.getContentResolver().openInputStream(file.getUri());                }            } else {                in = new FileInputStream(destFile);            }        } catch (FileNotFoundException e) {            e.printStackTrace();        }        return in;    }    public static OutputStream getOutputStream(Context context, File destFile) {        OutputStream out = null;        try {            if (!canWrite(destFile) && isOnExtSdCard(destFile, context)) {                DocumentFile file = DocumentsUtils.getDocumentFile(destFile, false, context);                if (file != null && file.canWrite()) {                    out = context.getContentResolver().openOutputStream(file.getUri());                }            } else {                out = new FileOutputStream(destFile);            }        } catch (FileNotFoundException e) {            e.printStackTrace();        }        return out;    }    public static boolean saveTreeUri(Context context, String rootPath, Uri uri) {        DocumentFile file = DocumentFile.fromTreeUri(context, uri);        if (file != null && file.canWrite()) {            SharedPreferences perf = PreferenceManager.getDefaultSharedPreferences(context);            perf.edit().putString(rootPath, uri.toString()).apply();            Log.e(TAG, "save uri" + rootPath);            return true;        } else {            Log.e(TAG, "no write permission: " + rootPath);        }        return false;    }    public static boolean checkWritableRootPath(Context context, String rootPath) {        File root = new File(rootPath);        if (!root.canWrite()) {            if (DocumentsUtils.isOnExtSdCard(root, context)) {                Log.i(TAG,"lum_ isOnExtSdCard");                DocumentFile documentFile = DocumentsUtils.getDocumentFile(root, true, context);                return documentFile == null || !documentFile.canWrite();            } else {                Log.i(TAG,"lum_2 get perf");                SharedPreferences perf = PreferenceManager.getDefaultSharedPreferences(context);                String documentUri = perf.getString(rootPath, "");                if (documentUri == null || documentUri.isEmpty()) {                    return true;                } else {                    DocumentFile file = DocumentFile.fromTreeUri(context, Uri.parse(documentUri));                    return !(file != null && file.canWrite());                }            }        }        return false;    }}

4.MainActivity.java

import android.Manifest;import android.content.Context;import android.content.DialogInterface;import android.content.Intent;import android.content.pm.PackageManager;import android.net.Uri;import android.os.storage.StorageManager;import android.os.storage.StorageVolume;import android.provider.Settings;import android.support.v4.app.ActivityCompat;import android.support.v4.content.ContextCompat;import android.support.v7.app.AlertDialog;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.Toast;import java.io.File;import java.io.IOException;import java.io.OutputStream;import java.lang.reflect.Array;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity implements View.OnClickListener{    private String TAG = "MainActivity: ";    private String rootPath = "";  //外置 SD 卡路径    private List unPermissionList = new ArrayList(); //申请未得到授权的权限列表    private final int RequestCode = 100;//权限请求码    private AlertDialog mPermissionDialog;    private String mPackName ;  //获取 a'p'k 包名    private String[] permissionList = new String[]{    //申请的权限列表            Manifest.permission.READ_EXTERNAL_STORAGE,            Manifest.permission.WRITE_EXTERNAL_STORAGE,    };    private Button mButton;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        checkPermission();        mPackName = getPackageName();        rootPath = getStoragePath(this, true);  //获取 可以插拔的 sd 卡  路径        Log.i(TAG, "lum rootPath: " + rootPath);        if (DocumentsUtils.checkWritableRootPath(this, rootPath)) {   //检查sd卡路径是否有 权限 没有显示dialog            showOpenDocumentTree();        }        mButton = (Button) findViewById(R.id.but_id);        mButton.setOnClickListener(this);    }    private void showOpenDocumentTree() {        Intent intent = null;        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {            StorageManager sm = getSystemService(StorageManager.class);            StorageVolume volume = sm.getStorageVolume(new File(rootPath));            if (volume != null) {                intent = volume.createAccessIntent(null);            }        }        if (intent == null) {            intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);        }        startActivityForResult(intent, DocumentsUtils.OPEN_DOCUMENT_TREE_CODE);    }    @Override    public void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        switch (requestCode) {            case DocumentsUtils.OPEN_DOCUMENT_TREE_CODE:                if (data != null && data.getData() != null) {                    Uri uri = data.getData();                    DocumentsUtils.saveTreeUri(this, rootPath, uri);                    Log.i(TAG,"lum_uri : "  + uri);                }                break;            default:                break;        }    }    //权限判断和申请    public void checkPermission() {        unPermissionList.clear();//清空申请的没有通过的权限        //逐个判断是否还有未通过的权限        for (int i = 0; i < permissionList.length; i++) {            if (ContextCompat.checkSelfPermission(this, permissionList[i]) !=                    PackageManager.PERMISSION_GRANTED) {                unPermissionList.add(permissionList[i]);//添加还未授予的权限到unPermissionList中            }        }        //有权限没有通过,需要申请        if (unPermissionList.size() > 0) {            ActivityCompat.requestPermissions( this,permissionList, 100);            Log.i(TAG, "check 有权限未通过");        } else {            //权限已经都通过了,可以将程序继续打开了            Log.i(TAG, "check 权限都已经申请通过");        }    }    /**     * 5.请求权限后回调的方法     *     * @param requestCode  是我们自己定义的权限请求码     * @param permissions  是我们请求的权限名称数组     * @param grantResults 是我们在弹出页面后是否允许权限的标识数组,数组的长度对应的是权限     *                     名称数组的长度,数组的数据0表示允许权限,-1表示我们点击了禁止权限     */    @Override    public void onRequestPermissionsResult(int requestCode, String[] permissions,                                           int[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        Log.i(TAG,"申请结果反馈");        boolean hasPermissionDismiss = false;        if (100 == requestCode) {            for (int i = 0; i < grantResults.length; i++) {                if (grantResults[i] == -1) {                    hasPermissionDismiss = true; //有权限没有通过                    Log.i(TAG,"有权限没有被通过");                    break;                }            }        }        if (hasPermissionDismiss) {//如果有没有被允许的权限            showPermissionDialog();        } else {            //权限已经都通过了,可以将程序继续打开了            Log.i(TAG, "onRequestPermissionsResult 权限都已经申请通过");        }    }    /**     * 不再提示权限时的展示对话框     */    private void showPermissionDialog() {        Log.i(TAG,"mPackName: " + mPackName);        if (mPermissionDialog == null) {            mPermissionDialog = new AlertDialog.Builder(this)                    .setMessage("已禁用权限,请手动授予")                    .setPositiveButton("设置", new DialogInterface.OnClickListener() {                        @Override                        public void onClick(DialogInterface dialog, int which) {                            cancelPermissionDialog();                            Uri packageURI = Uri.parse("package:" + mPackName);     //去设置里面设置                            Intent intent = new Intent(Settings.                                    ACTION_APPLICATION_DETAILS_SETTINGS, packageURI);                            startActivity(intent);                        }                    })                    .setNegativeButton("取消", new DialogInterface.OnClickListener() {                        @Override                        public void onClick(DialogInterface dialog, int which) {                            //关闭页面或者做其他操作                            cancelPermissionDialog();                        }                    })                    .create();        }        mPermissionDialog.show();    }    private void cancelPermissionDialog() {        mPermissionDialog.cancel();    }    @Override    public void onClick(View view) {        switch (view.getId()){            case R.id.but_id:                Log.i(TAG,"点击");                try {                    writeDataToSD();                } catch (IOException e) {                    e.printStackTrace();                }        }    }    /**     * 通过反射调用获取内置存储和外置sd卡根路径(通用)     *     * @param mContext    上下文     * @param is_removale 是否可移除,false返回内部存储路径,true返回外置SD卡路径     * @return     */    private static String getStoragePath(Context mContext, boolean is_removale) {        String path = "";        //使用getSystemService(String)检索一个StorageManager用于访问系统存储功能。        StorageManager mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);        Class<?> storageVolumeClazz = null;        try {            storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");            Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");            Method getPath = storageVolumeClazz.getMethod("getPath");            Method isRemovable = storageVolumeClazz.getMethod("isRemovable");            Object result = getVolumeList.invoke(mStorageManager);            for (int i = 0; i < Array.getLength(result); i++) {                Object storageVolumeElement = Array.get(result, i);                path = (String) getPath.invoke(storageVolumeElement);                boolean removable = (Boolean) isRemovable.invoke(storageVolumeElement);                if (is_removale == removable) {                    return path;                }            }        } catch (Exception e) {            e.printStackTrace();        }        return path;    }    public  void writeDataToSD() throws IOException {        //写文件的例子 文件不存在,会创建        String  str = "just a test\n";        String strRead = "";        String  sdkOut = getStoragePath(this,true);  //获取 可以插拔的 sd 卡  路径        String  filePath = sdkOut +File.separator+"Android"+File.separator+"data"+File.separator+getPackageName()+ "/test";        Log.i(TAG,"lum_ sdkOut: " + filePath);        File file = new File(filePath);        if (!file.exists()){            file.mkdirs();            Log.i(TAG,"创建文件夹:" + filePath);        }        String  fileWritePath = filePath + "/test.txt";        File fileWrite = new File(fileWritePath);        Log.i(TAG,"lum  准备写入" );        try {            OutputStream outputStream = DocumentsUtils.getOutputStream(this,fileWrite);  //获取输出流            //  OutputStream outputStream = new FileOutputStream(fileWrite);            outputStream.write(str.getBytes());            outputStream.close();            Log.i(TAG,"lum  写入成功" );            Toast.makeText(this,"路径:" + fileWritePath + "成功",Toast.LENGTH_SHORT ).show();        } catch (IOException e) {            e.printStackTrace();            Log.i(TAG,"lum  写入失败" );            Toast.makeText(this,"路径:" + fileWritePath + "失败",Toast.LENGTH_SHORT ).show();        }        /*        //读取文件 的例子        try {            InputStream is = DocumentsUtils.getInputStream(this,fileWritePath);            InputStreamReader input = new InputStreamReader(is, "UTF-8");            BufferedReader reader = new BufferedReader(input);            while ((str = reader.readLine()) != null) {                strRead  +=  str;            }            Log.i(TAG,"lum:读取的文件是 " +  strRead);        } catch (FileNotFoundException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }*/    }}

参考链接:https://blog.csdn.net/xingnan4414/article/details/79388972

https://blog.csdn.net/u010784887/article/details/53560025

https://blog.csdn.net/omnispace/article/details/79302862

https://juejin.im/post/58b557de128fe10065e93cc8

https://blog.csdn.net/qq_36467463/article/details/88691726

更多相关文章

  1. java拷贝文件夹和android设置文件权限
  2. java|android加载src路径下面的图片文件
  3. 关于android录音权限被用户禁用的问题解决方案
  4. android动态申请拍照获取照片权限
  5. Android判断是否有拍照权限
  6. Mac通过Android aapt解析apk包名、版本号、权限等信息

随机推荐

  1. Android(安卓)客户端通过内置API(HttpClie
  2. android开发新浪微博客户端
  3. Android 手绘 - 支持保存为图片
  4. Android常用控件之ExpandableList的使用
  5. Windows Mobile 和 Android(安卓)对比分
  6. Activity 属性设置大全
  7. 解决gradle下载慢,下载失败的办法
  8. android创建漂亮对话框
  9. Android 4.0 开发者指南(27) —— Resour
  10. Android+JNI调用–文件操作