web-dev-qa-db-fra.com

Obtenir le vrai chemin de l'URI du fichier dans sdcard Marshmallow

Je veux choisir les fichiers qui existent dans sdcard pas dans la mémoire de stockage interne et le télécharger mais je ne parviens pas à obtenir son chemin pour obtenir sa taille. J'ai commencé une intention de choisir un fichier en utilisant le code ci-dessous:

 intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
 intent.addCategory(Intent.CATEGORY_OPENABLE);
 intent.setType("*/*");
 String[] mimetypes = {"application/*"};
 intent.putExtra(Intent.EXTRA_MIME_TYPES, mimetypes);
 startActivityForResult(
      Intent.createChooser(intent, "Select a File to Upload"), FILE_SELECT_CODE);

Pour obtenir le chemin d'accès au fichier, j'utilise cette réponse et son fonctionnement, sauf si l'utilisateur sélectionne un fichier quelconque sur sdcard (amovible). Quand je débogue le code et trouve que type n'est pas primaire donc il ne va pas aller dans cette condition:

if("primary".equalsIgnoreCase(type)){
     return Environment.getExternalStorageDirectory() + "/" + split[1];
} 

Alors ma question est: qu'est-ce que ce sera d'autre? c'est-à-dire si le type n'est pas primaire? Comment pouvons-nous obtenir le chemin d'accès au fichier dans ce cas? J'ai cherché beaucoup de questions et de tutoriel, il n'y en a pas d'autres. J'ai également essayé une autre partie de cette réponse mais cela ne fonctionne pas car System.getenv() renvoie null pour " SECONDARY_STORAGE " et sdcard pour " EXTERNAL_STORAGE ". Je reçois une exception de fichier non trouvé lorsque j'essaie:

if ("primary".equalsIgnoreCase(type)) {
    return Environment.getExternalStorageDirectory() + "/" + split[1];
}else{
    return System.getenv("EXTERNAL_STORAGE") + "/" + split[1];
}

Uri et doc Id pour le fichier ressemblent à: 

Uri : content: //com.Android.externalstorage.documents/document/0EF9-3110%3Adevice-2016-12-02-130553.png

docId : 0EF9-3110: device-2016-12-02-130553.png

De l'aide ??

6
Jaiprakash Soni

Après avoir passé du temps sur Android Device Manager, j'ai trouvé une solution. La voici:

Si le type de document id n'est pas primaire, alors je crée un chemin en utilisant:

filePath = "/storage/" + type + "/" + split[1];

EDIT: en cas de DocumentUri, sélectionnez contentUri sur la base du type de fichier

Voici la fonction complète:

public static String getRealPathFromURI_API19(Context context, Uri uri) {
    String filePath = "";

    // 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];
        } else {

            if (Build.VERSION.SDK_INT > 20) {
                    //getExternalMediaDirs() added in API 21
                    File extenal[] = context.getExternalMediaDirs();
                    if (extenal.length > 1) {
                        filePath = extenal[1].getAbsolutePath();
                        filePath = filePath.substring(0, filePath.indexOf("Android")) + split[1];
                    }
             }else{
                    filePath = "/storage/" + type + "/" + split[1];
             }
            return filePath;
        }

    } else if (isDownloadsDocument(uri)) {
        // DownloadsProvider
        final String id = DocumentsContract.getDocumentId(uri);
        //final Uri contentUri = ContentUris.withAppendedId(
        // Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

        Cursor cursor = null;
        final String column = "_data";
        final String[] projection = {column};

        try {
            cursor = context.getContentResolver().query(uri, projection, null, null, null);
            if (cursor != null && cursor.moveToFirst()) {
                final int index = cursor.getColumnIndexOrThrow(column);
                String result = cursor.getString(index);
                cursor.close();
                return result;
            }
        } finally {
            if (cursor != null)
                cursor.close();
        }
    } else if (DocumentsContract.isDocumentUri(context, uri)) {
        // MediaProvider
        String wholeID = DocumentsContract.getDocumentId(uri);

        // Split at colon, use second item in the array
        String[] ids = wholeID.split(":");
        String id;
        String type;
        if (ids.length > 1) {
            id = ids[1];
            type = ids[0];
        } else {
            id = ids[0];
            type = ids[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[]{id};
        final String column = "_data";
        final String[] projection = {column};
        Cursor cursor = context.getContentResolver().query(contentUri, 
            projection, selection, selectionArgs, null);

        if (cursor != null) {
            int columnIndex = cursor.getColumnIndex(column);

            if (cursor.moveToFirst()) {
                filePath = cursor.getString(columnIndex);
            }
            cursor.close();
        }
        return filePath;
    } else {
        String[] proj = {MediaStore.Audio.Media.DATA};
        Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null);
        if (cursor != null) {
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
            if (cursor.moveToFirst())
                filePath = cursor.getString(column_index);
            cursor.close();
        }


        return filePath;
    }
    return null;
}
9
Jaiprakash Soni

Changez votre code de téléchargement. Quelque part vous aurez

FileInputStream fis = new FileInputStream(path);

Changer en

InputStream is = getContentResolver().openInputStream(uri);

Alors utilisez directement l'uri. Pas besoin d'un chemin de fichier.

3
greenapps

Il est assez facile d'implémenter FileProvider sur votre application. Vous devez d’abord ajouter une balise FileProvider dans AndroidManifest.xml sous la balise, comme ci-dessous: AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
    ...
    <application
        ...
        <provider
            Android:name="Android.support.v4.content.FileProvider"
            Android:authorities="${applicationId}.provider"
            Android:exported="false"
            Android:grantUriPermissions="true">
            <meta-data
                Android:name="Android.support.FILE_PROVIDER_PATHS"
                Android:resource="@xml/provider_paths"/>
        </provider>
    </application>
</manifest>

Et créez ensuite un fichier provider_paths.xml dans le dossier xml sous le dossier res. Un dossier peut être nécessaire pour créer s'il n'existe pas.

res/xml/provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <external-path name="external_files" path="."/>
</paths>

Terminé! FileProvider est maintenant déclaré et prêt à être utilisé.

La dernière étape consiste à modifier la ligne de code ci-dessous dans MainActivity.Java.

Uri photoURI = Uri.fromFile(createImageFile());
to



 Uri photoURI = FileProvider.getUriForFile(MainActivity.this,
            BuildConfig.APPLICATION_ID + ".provider",
            createImageFile());

Et fait ! Votre application devrait maintenant fonctionner parfaitement sur toutes les versions d'Android, y compris Android Nougat. Yah!

0
g7pro