Publicado en Android

Cómo acceder a archivos desde el almacenamiento compartido CRUD ContentProvider AndroidX Kotlin


Google durante el tiempo a variado la API de acceso a los archivos del sistema Android, a cada versión a aumentado la seguridad hasta llegar a tal punto que no permite acceder al sistema propio de archivos como se hacia antés, pero por otro lado ofrece una API solida mediante proveedores de contenido.

Como el usuario participa en la selección de los archivos o directorios a los que puede acceder la app, este mecanismo no requiere ningún permiso del sistema

Crear un archivo

Para crear un archivo usando ContentProvider

private fun createFile(fileName:String = "sample.txt",mineType: String = "text/plain") {
    val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
        addCategory(Intent.CATEGORY_OPENABLE)
        type = mineType
        putExtra(Intent.EXTRA_TITLE, fileName)
    }
    startActivityForResult(intent, PICK_CREATE_FILE)
}

Su uso es llamar la función createFile con el nombre del archivo a crear y el tipo de contenido que tendra, en este caso texto plano su minetype es text/plain

createFile("demo.txt", "text/plain")

El mismo sistema android se encargará de mostrar el selector de archivo para así poderlo guardar en el directorio correspondiente, hasta poderlo subir a GoogleDrive

Al crear un archivo el selector de archivos nos devolvera una uri del archivo donde se encuentra, no confundir uri con el path (obsoleto), el uri del archivo creador se puede obtener con la devuelta en onActivityResult

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (resultCode == Activity.RESULT_OK) {
        when (requestCode) {
            PICK_CREATE_FILE -> {
                data?.data?.also { uri ->
                   //uri del archivo creado
                }
            }
        }
    }
}

Se obtiene el uri para operar con el ContenProvider, para escribir contenido ver sección Modificar un archivo para saber como añadir contenido dentro de el archivo.

Seleccionar un archivo

Para abrir un archivo con ContenProvider, debemos invocar el selector de archivos por parte del sistema android y que nos devuelve el uri.

private fun openFile(mineType: String = "*/*") {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
        addCategory(Intent.CATEGORY_OPENABLE)
        type = mineType
    }
    startActivityForResult(intent, PICK_OPEN_FILE)
}

Con el método openFile podemos abrir el selector nativo que nos ofrece el sistema Android, se puede indicar solamente el tipo de archivo que requerimos, en este caso como se trabaja con texto plano text/plain

openFile("text/plain")

Luego de selecionar el archivo, nos devolverá su uri en onActivityResult

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (resultCode == Activity.RESULT_OK) {
        when (requestCode) {
            ...            
            PICK_OPEN_FILE -> {
                data?.data?.also { uri ->
                //uri del archivo selecionado
                }
        }
    }
}

Tras obtener el uri del archivo podemos operar con el ContentProvider, para recuperar la información de un archivo ver sección Leer un archivo

Modificar un archivo

Para añadir contenido aun archivo usando ContentProvider

@Throws(IOException::class)
private fun writeTextToUri(uri: Uri, content: String) {

    requireActivity().contentResolver.openFileDescriptor(uri, "w")?.use { it ->
        FileOutputStream(it.fileDescriptor).use { fileOutputStream ->
            fileOutputStream.write(
                content.toByteArray()
            )
            fileOutputStream.close()
        }
    }
}

Su uso writeTextToUri le indicamos el uri del archivo y el contenido a añadir

writeTextToUri(uri,"eso es contenido de prueba usando ContentProvider de Android")

Si usamos una app de gestión de archivos podemos comprobar si se a creado el archivo y su contenido correctamente. Para controlar si a ocurrido un error al querer añadir contenido al archivo, se puede recurrir a encapsular con try..catch IOException

PICK_CREATE_FILE -> {
    data?.data?.also { uri ->
        try {
            writeTextToUri(uri,"eso es contenido de prueba usando ContentProvider de Android")
        } catch ( e : IOException) {
            e.printStackTrace()
        }
    }
}

Leer un archivo

Para recuperar el contenido de un archivo usando ContentProvider

@Throws(IOException::class)
private fun readTextFromUri(uri: Uri): String {
    val stringBuilder = StringBuilder()
    requireActivity().contentResolver.openInputStream(uri)?.use { inputStream ->
        BufferedReader(InputStreamReader(inputStream)).use { reader ->
            var line: String? = reader.readLine()
            while (line != null) {
                stringBuilder.append(line)
                line = reader.readLine()
            }
            reader.close()
        }
    }
    return stringBuilder.toString()
}

Su uso readTextFromUri le indicamos el uri del archivo y nos devolverá la cadena de texto con el contenido.

val contenido = readTextFromUri(uri)

En caso de comprobar si el archivo existe justo el momento de leer su contenido, encapsular el código dentro de un bloque try…catch…IOException

PICK_OPEN_FILE -> {
    data?.data?.also { uri ->
        try {
            val contenido = readTextFromUri(uri)
        } catch ( e : IOException) {
            e.printStackTrace()
        }
    }
}

Autor:

Desarrollador freelance programador apasionado por el arte de programar, amante del auto aprendizaje y interesado por la tecnología en general.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios .