Android判断有无外置SD卡(TF卡),并读写文件

编程入门 行业动态 更新时间:2024-10-24 21:34:36

Android判断有无<a href=https://www.elefans.com/category/jswz/34/1758943.html style=外置SD卡(TF卡),并读写文件"/>

Android判断有无外置SD卡(TF卡),并读写文件

转载来源:

1.相关方法说明:

2.Android Manifest.xml 添加权限

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <uses-permission
        android:name="android.permission.WRITE_MEDIA_STORAGE"
        tools:ignore="ProtectedPermissions" />

    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
    tools:ignore="ProtectedPermissions" /> <!-- 允许应用读取低级别的系统日志文件 -->

 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<String> 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<String> unPermissionList = new ArrayList<String>(); //申请未得到授权的权限列表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;@Overrideprotected 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卡路径是否有 权限 没有显示dialogshowOpenDocumentTree();}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);}@Overridepublic 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表示我们点击了禁止权限*/@Overridepublic 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() {@Overridepublic 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() {@Overridepublic void onClick(DialogInterface dialog, int which) {//关闭页面或者做其他操作cancelPermissionDialog();}}).create();}mPermissionDialog.show();}private void cancelPermissionDialog() {mPermissionDialog.cancel();}@Overridepublic 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 blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}
*/}
}

参考链接:

更多推荐

Android判断有无外置SD卡(TF卡),并读写文件

本文发布于:2023-06-27 08:09:11,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/908572.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:外置   有无   文件   Android   TF

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!