web-dev-qa-db-fra.com

Comment obtenir le chemin du fichier à partir de l'URI dans Android Oreo (8.1) ou supérieur

Comportement attend

Lorsque je sélectionne le fichier qui est stocké dans "Télécharger", il devrait pouvoir récupérer son nom de fichier et son chemin

Comportement réel

Lorsque je sélectionne le fichier qui est stocké dans "Télécharger", il renvoie null.

étapes pour reproduire le problème

  1. Lorsque la méthode de sélection de fichiers est appelée, elle affiche les dossiers dans Android
  2. Accédez aux téléchargements, sélectionnez un fichier
  3. Il renvoie null en obtenant le chemin réel à partir de l'URI

Voici le code que j'ai implémenté

public static String getPath(final Context context, final Uri uri) {
   String id = DocumentsContract.getDocumentId(uri);
   if (!TextUtils.isEmpty(id)) {
      if (id.startsWith("raw:")) {
          return id.replaceFirst("raw:", "");
      }
      try {
         final boolean isOreo = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
         String stringContentURI;
         Uri contentUri;
         if(isOreo){ 
            stringContentURI = "content://downloads/my_downloads";
         }else{
            stringContentURI = "content://downloads/public_downloads";
         }
         contentUri = ContentUris.withAppendedId(
                    Uri.parse(stringContentURI), Long.valueOf(id));
         return getDataColumn(context, contentUri, null, null);
      } catch (NumberFormatException e) {
         return null;
      }
   }
}

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

Cependant, cela fonctionne lors de la sélection de fichiers dans d'autres dossiers dans Android

S'il vous plaît donnez votre avis. Merci tout le monde :)

6
ryosu

Pour l'instant, la meilleure approche pour obtenir le chemin est:

Obtenir un fichier physique depuis l'URI en tant que InputStream, ContentResolver.openInputStream() vous permet d'accéder au contenu d'un fichier sans connaître son vrai chemin

String id = DocumentsContract.getDocumentId(uri);
InputStream inputStream = getContentResolver().openInputStream(uri);

puis l'écrire en tant que fichier temporaire dans le stockage mis en cache

File file = new File(getCacheDir().getAbsolutePath()+"/"+id);
writeFile(inputStream, file);
String filePath = file.getAbsolutePath();

Voici la méthode pour écrire un fichier temporaire dans le stockage mis en cache

void writeFile(InputStream in, File file) {
     OutputStream out = null;
     try {
          out = new FileOutputStream(file);
          byte[] buf = new byte[1024];
          int len;
          while((len=in.read(buf))>0){
            out.write(buf,0,len);
          }
     } catch (Exception e) {
          e.printStackTrace();
     }
     finally {
          try {
            if ( out != null ) {
                 out.close();
            }
            in.close();
          } catch ( IOException e ) {
               e.printStackTrace();
          }
     }
}

Je ne sais pas si c'est la meilleure façon de le faire, mais le code fonctionne correctement: D

6
ryosu

Voici une autre solution que j'ai trouvée à partir de ce Gist. FileUtils.Java

Voici comment l'utiliser.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    Uri uri = data.getData();
    File originalFile = new File(FileUtils.getRealPath(this,uri));
}
0
NIMROD MAINA

Voici ce que je viens de proposer (il est testé sur Android Pie & suppose une carte SD):

private String getParentDirectory(@NonNull Uri uri) {
    String uriPath = uri.getPath();
    String filePath = Environment.getExternalStorageDirectory().getAbsolutePath();
    if(uriPath != null) {filePath = new File(filePath.concat("/" + uriPath.split(":")[1])).getParent();}
    return filePath;
}

private String getAbsolutePath(@NonNull Uri uri) {
    String uriPath = uri.getPath();
    String filePath = Environment.getExternalStorageDirectory().getAbsolutePath();
    if(uriPath != null) {filePath = filePath.concat("/" + uriPath.split(":")[1]);}
    return filePath;
}
0
Martin Zeitler