Android 文件选择获取路径(亲测并踩坑)

权限配置

open failed: EACCES (Permission denied)

必须按照下面的方式配置否则报错,下面是解决方法

首先需要检查是否添加读写权限。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
然后再确认是否在程序中动态获取权限,获取方法如下,需要在调用相机之前进行获取。
ActivityCompat.requestPermissions(MainActivity.this,
        new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},
        1);
最后在AndroidManifest.xml文件中的application中添加如下代码。
android:requestLegacyExternalStorage="true"

启动文件选择

在 onCreate里注册

activityResultLauncher = registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()
        ) {
            val data = it.data
            val resultCode = it.resultCode
            val fileName: String?
            if (PickUtils.getPath(this, data?.data).also { name ->
                    fileName = name
                } != null) {
                val name = PickUtils.getFileName(this, data?.data)
                val fileTemp = File(fileName)
                if (fileTemp.exists()) {
                    file = fileTemp
                    tvFileName.text = fileName
                } else {
                    file = null
                    tvFileName.text = "文件不存在,请重新选择~"
                }
            }
        }

在跳转的地方调用

val intent = Intent(Intent.ACTION_GET_CONTENT);
            //intent.setType(“image/*”);//选择图片
            //intent.setType(“audio/*”); //选择音频
            //intent.setType(“video/*”); //选择视频 (mp4 3gp 是android支持的视频格式)
            //intent.setType(“video/*;image/*”);//同时选择视频和图片
            intent.type = "*/*";//无类型限制
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            activityResultLauncher?.launch(intent)

PickUtils代码

import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class PickUtils {
  public static final String DOCUMENTS_DIR = "documents";

  @SuppressLint("NewApi")
  public static String getPath(final Context context, final Uri uri) {
    final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
    // DocumentProvider
    if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
      // ExternalStorageProvider
      if (isExternalStorageDocument(uri)) {
        final String docId = DocumentsContract.getDocumentId(uri);
        final String[] split = docId.split(":");
        final String type = split[0];
        if ("primary".equalsIgnoreCase(type)) {
          return Environment.getExternalStorageDirectory() + "/" + split[1];
        }
      }
      // DownloadsProvider
      else if (isDownloadsDocument(uri)) {
        final String id = DocumentsContract.getDocumentId(uri);
        if (id != null && id.startsWith("raw:")) {
          return id.substring(4);
        }
        String[] contentUriPrefixesToTry = new String[]{
            "content://downloads/public_downloads",
            "content://downloads/my_downloads"
        };
        for (String contentUriPrefix : contentUriPrefixesToTry) {
          try {
            // note: id 可能为字符串,如在华为10.0系统上,选择文件后id为:"msf:254",导致转Long异常
            Uri contentUri = ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.parseLong(id));
            String path = getDataColumn(context, contentUri, null, null);
            if (path != null && !path.equals("")) {
              return path;
            }
          } catch (Exception e) {
          }
        }
        // path could not be retrieved using ContentResolver, therefore copy file to accessible cache using streams
        String fileName = getFileName(context, uri);
        File cacheDir = getDocumentCacheDir(context);
        File file = generateFileName(fileName, cacheDir);
        String destinationPath = null;
        if (file != null) {
          destinationPath = file.getAbsolutePath();
          saveFileFromUri(context, uri, destinationPath);
        }
        return destinationPath;
      }
      // MediaProvider
      else if (isMediaDocument(uri)) {
        final String docId = DocumentsContract.getDocumentId(uri);
        final String[] split = docId.split(":");
        final String type = split[0];
        Uri contentUri = null;
        if ("image".equals(type)) {
          contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        } else if ("video".equals(type)) {
          contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
        } else if ("audio".equals(type)) {
          contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        }
        final String selection = "_id=?";
        final String[] selectionArgs = new String[]{split[1]};
        return getDataColumn(context, contentUri, selection, selectionArgs);
      }
    }
    // MediaStore (and general)
    else if ("content".equalsIgnoreCase(uri.getScheme())) {
      String path = getDataColumn(context, uri, null, null);
      if (path != null && !path.equals("")) return path;
      // path could not be retrieved using ContentResolver, therefore copy file to accessible cache using streams
      String fileName = getFileName(context, uri);
      File cacheDir = getDocumentCacheDir(context);
      File file = generateFileName(fileName, cacheDir);
      String destinationPath = null;
      if (file != null) {
        destinationPath = file.getAbsolutePath();
        saveFileFromUri(context, uri, destinationPath);
      }
      return destinationPath;
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
      return uri.getPath();
    }
    return null;
  }

  /**
   * @param uri The Uri to check.
   * @return Whether the Uri authority is ExternalStorageProvider.
   */
  public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
  }

  /**
   * @param uri The Uri to check.
   * @return Whether the Uri authority is DownloadsProvider.
   */
  public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
  }

  /**
   * @param uri The Uri to check.
   * @return Whether the Uri authority is MediaProvider.
   */
  public static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
  }

  public static String getDataColumn(Context context, Uri uri, String selection,
                                     String[] selectionArgs) {
    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {column};
    String path = "";
    try {
      cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
          null);
      if (cursor != null && cursor.moveToFirst()) {
        final int column_index = cursor.getColumnIndexOrThrow(column);
        path = cursor.getString(column_index);
        return path;
      }
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (cursor != null)
        cursor.close();
    }
    return path;
  }

  public static String getFileName(@NonNull Context context, Uri uri) {
    String mimeType = context.getContentResolver().getType(uri);
    String filename = null;
    if (mimeType == null && context != null) {
      String path = getPath(context, uri);
      if (path == null) {
        filename = getName(uri.toString());
      } else {
        File file = new File(path);
        filename = file.getName();
      }
    } else {
      Cursor returnCursor = context.getContentResolver().query(uri, null,
          null, null, null);
      if (returnCursor != null) {
        int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
        returnCursor.moveToFirst();
        filename = returnCursor.getString(nameIndex);
        returnCursor.close();
      }
    }
    String[] filename_s = filename.split("\\.", 2);
    return filename_s[0];
  }

  public static String getName(String filename) {
    if (filename == null) {
      return null;
    }
    int index = filename.lastIndexOf('/');
    return filename.substring(index + 1);
  }

  public static File getDocumentCacheDir(@NonNull Context context) {
    Log.d("PickUtils", "getDocumentCacheDir");
    File dir = new File(context.getCacheDir(), DOCUMENTS_DIR);
    if (!dir.exists()) {
      dir.mkdirs();
    }
    return dir;
  }

  @Nullable
  public static File generateFileName(@Nullable String name, File directory) {
    if (name == null) {
      return null;
    }
    File file = new File(directory, name);
    if (file.exists()) {
      String fileName = name;
      String extension = "";
      int dotIndex = name.lastIndexOf('.');
      if (dotIndex > 0) {
        fileName = name.substring(0, dotIndex);
        extension = name.substring(dotIndex);
      }
      int index = 0;
      while (file.exists()) {
        index++;
        name = fileName + '(' + index + ')' + extension;
        file = new File(directory, name);
      }
    }
    try {
      if (!file.createNewFile()) {
        return null;
      }
    } catch (IOException e) {
      return null;
    }
    return file;
  }

  private static void saveFileFromUri(Context context, Uri uri, String destinationPath) {
    InputStream is = null;
    BufferedOutputStream bos = null;
    try {
      is = context.getContentResolver().openInputStream(uri);
      bos = new BufferedOutputStream(new FileOutputStream(destinationPath, false));
      byte[] buf = new byte[1024];
      is.read(buf);
      do {
        bos.write(buf);
      } while (is.read(buf) != -1);
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        if (is != null) is.close();
        if (bos != null) bos.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值