Android: ¿Cómo obtener un URI de archivo de un URI de contenido?


En mi aplicación, el usuario debe seleccionar un archivo de audio que la aplicación luego maneja. El problema es que para que la aplicación haga lo que quiero que haga con los archivos de audio, necesito que el URI esté en formato de archivo. Cuando uso el reproductor de música nativo de Android para buscar el archivo de audio en la aplicación, el URI es un URI de contenido, que se ve así:

content://media/external/audio/media/710

Sin embargo, usando la popular aplicación de administrador de archivos Astro, obtengo lo siguiente:

file:///sdcard/media/audio/ringtones/GetupGetOut.mp3

Este último es mucho más accesible para mí para trabajar con, pero por supuesto quiero que la aplicación tenga funcionalidad con el archivo de audio que el usuario elija independientemente del programa que use para navegar por su colección. Así que mi pregunta es, ¿hay alguna manera de convertir el URI de estilo content:// en un URI file://? De lo contrario, ¿qué me recomendarías para resolver este problema? Aquí está el código que llama al selector, para referencia:

Intent ringIntent = new Intent();
ringIntent.setType("audio/mp3");
ringIntent.setAction(Intent.ACTION_GET_CONTENT);
ringIntent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(Intent.createChooser(ringIntent, "Select Ringtone"), SELECT_RINGTONE);

Hago lo siguiente con el URI de contenido:

m_ringerPath = m_ringtoneUri.getPath();
File file = new File(m_ringerPath);

A continuación, hacer algunas cosas FileInputStream con said file.

Author: ROMANIA_engineer, 2011-04-14

6 answers

Simplemente use getContentResolver().openInputStream(uri) para obtener un InputStream de un URI.

Http://developer.android.com/reference/android/content/ContentResolver.html#openInputStream(android.net.Uri)

 119
Author: Jason LeBrun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-15 13:50:04

Puede usar el Solucionador de contenido para obtener una ruta file:// desde el URI content://:

String filePath = null;
Uri _uri = data.getData();
Log.d("","URI = "+ _uri);                                       
if (_uri != null && "content".equals(_uri.getScheme())) {
    Cursor cursor = this.getContentResolver().query(_uri, new String[] { android.provider.MediaStore.Images.ImageColumns.DATA }, null, null, null);
    cursor.moveToFirst();   
    filePath = cursor.getString(0);
    cursor.close();
} else {
    filePath = _uri.getPath();
}
Log.d("","Chosen path = "+ filePath);
 39
Author: nobre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-01 14:55:35

Tratar de manejar el URI con content:// scheme llamando a ContentResolver.query() no es una buena solución. En HTC Desire corriendo 4.2.2 usted podría obtener NULL como resultado de la consulta.

¿Por qué no usar ContentResolver en su lugar? https://stackoverflow.com/a/29141800/3205334

 5
Author: Darth Raven,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:45

Si tienes un Uri de contenido con content://com.externalstorage... puedes usar este método para obtener la ruta absoluta de una carpeta o archivo en Android 19 o superior.

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)) {
        System.out.println("getPath() uri: " + uri.toString());
        System.out.println("getPath() uri authority: " + uri.getAuthority());
        System.out.println("getPath() uri path: " + uri.getPath());

        // ExternalStorageProvider
        if ("com.android.externalstorage.documents".equals(uri.getAuthority())) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];
            System.out.println("getPath() docId: " + docId + ", split: " + split.length + ", type: " + type);

            // This is for checking Main Memory
            if ("primary".equalsIgnoreCase(type)) {
                if (split.length > 1) {
                    return Environment.getExternalStorageDirectory() + "/" + split[1] + "/";
                } else {
                    return Environment.getExternalStorageDirectory() + "/";
                }
                // This is for checking SD Card
            } else {
                return "storage" + "/" + docId.replace(":", "/");
            }

        }
    }
    return null;
}

Puede comprobar que cada parte del Uri está usando println. Los valores devueltos para mi tarjeta SD y la memoria principal del dispositivo se enumeran a continuación. Puede acceder y eliminar si el archivo está en la memoria, pero no pude eliminar el archivo de la tarjeta SD utilizando este método, solo leer u abrir d imagen usando esta ruta absoluta. Si usted tiene encontrar una solución para eliminar usando este método, por favor comparta. TARJETA SD

getPath() uri: content://com.android.externalstorage.documents/tree/612E-B7BF%3A/document/612E-B7BF%3A
getPath() uri authority: com.android.externalstorage.documents
getPath() uri path: /tree/612E-B7BF:/document/612E-B7BF:
getPath() docId: 612E-B7BF:, split: 1, type: 612E-B7BF

MEMORIA PRINCIPAL

getPath() uri: content://com.android.externalstorage.documents/tree/primary%3A/document/primary%3A
getPath() uri authority: com.android.externalstorage.documents
getPath() uri path: /tree/primary:/document/primary:
getPath() docId: primary:, split: 1, type: primary

Si desea obtener Uri con file:/// después de obtener la ruta, use

DocumentFile documentFile = DocumentFile.fromFile(new File(path));
documentFile.getUri() // will return a Uri with file Uri
 5
Author: Thracian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-06 14:12:31

Bueno, llego un poco tarde para responder, pero mi código está probado

Comprobar esquema de uri:

 byte[] videoBytes;

if (uri.getScheme().equals("content")){
        InputStream iStream =   context.getContentResolver().openInputStream(uri);
            videoBytes = getBytes(iStream);
        }else{
            File file = new File(uri.getPath());
            FileInputStream fileInputStream = new FileInputStream(file);     
            videoBytes = getBytes(fileInputStream);
        }

En la respuesta anterior convertí el uri de video en matriz de bytes, pero eso no está relacionado con la pregunta, Acabo de copiar mi código completo para mostrar el uso de FileInputStream y InputStream ya que ambos funcionan igual en mi código.

Usé la variable context que es getActivity() en mi Fragmento y en Activity simplemente es ActivityName.esto

context=getActivity(); //en fragmento

context=ActivityName.this;// en actividad

 1
Author: Umar Ata,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-05 11:28:50

Debe usar getContentResolver().openInputStream(uri) para obtener un InputStream de un URI. Porque es muy fácil y fácil de entender. Para más openInputStream(android.net.Uri)

 -1
Author: Harneet Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-23 15:06:36