14 - Almacenamiento de datos en un archivo de texto en la memoria interna

Otra posibilidad de almacenar datos en nuestro dispositivo Android es el empleo de un archivo de texto que se guardará en el almacenamiento interno del equipo (la otro posibilidad es almacenarlo en una tarjeta SD Card)

Problema 1:

Confeccionar un programa que permita almacenar notas en un control EditText y cuando se presione un botón almacenar los datos del EditText en un archivo de texto llamado "notas.txt".
Cada vez que se ingrese al programa verificar si existe el archivo de textos "notas.txt", proceder a su lectura y almacenamiento de datos en el EditText.

Crear un proyecto en Android Studio y definir como nombre: Proyecto016.

Para crear la interfaz visual primero disponemos un botón en la parte inferior del celular y luego de la pestaña "Text" seleccionamos un objeto de la clase EditText ("Multiline Text") y lo disponemos en la parte superior de la pantalla:

Archivos de texto memoria interna

A partir de la versión 2.3.0 de Android Studio las propiedades de cada objeto aparecen las más usadas en la pantalla principal. Si queremos ver todas las propiedades que tiene el objeto debemos seleccionar la opción "All Atributes" que aparece en la parte inferior de la ventana de propiedades.

Una vez que aparecen todas las propiedades inicializamos la propiedad background del EditText con el valor #ffff00 (que corresponde con el color amarillo):

Archivos de texto memoria interna

Finalmente procedemos a redimensionar el EditText por medio del mouse y configuramos la propiedad gravity tildando los valores top y left para que los datos que ingresa el operador aparezcan en la parte superior izquierda y no centrados:

Archivos de texto memoria interna

Podemos volver a ver la ventana de propiedades simplificadas presionando el ícono de dos flechitas de la parte superior derecha de la ventana de propiedades.

El código fuente en Kotlin de la aplicación:

package com.tutorialesprogramacionya.proyecto016

import android.app.Activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.io.OutputStreamWriter

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val boton1=findViewById<Button>(R.id.button)
        val et1=findViewById<EditText>(R.id.et1)
        if (fileList().contains("notas.txt")) {
            try {
                val archivo = InputStreamReader(openFileInput("notas.txt"))
                val br = BufferedReader(archivo)
                var linea = br.readLine()
                val todo = StringBuilder()
                while (linea != null) {
                    todo.append(linea + "\n")
                    linea = br.readLine()
                }
                br.close()
                archivo.close()
                et1.setText(todo)
            } catch (e: IOException) {
            }
        }

        boton1.setOnClickListener {
            try {
                val archivo = OutputStreamWriter(openFileOutput("notas.txt", Activity.MODE_PRIVATE))
                archivo.write(et1.text.toString())
                archivo.flush()
                archivo.close()
            } catch (e: IOException) {
            }
            Toast.makeText(this, "Los datos fueron grabados",Toast.LENGTH_SHORT).show()
            finish()
        }
    }
}

Veamos primero como grabamos datos en un archivo de texto. Esto se hace en la función lambda que le pasamos al método setOnClickListener del boton1:

Dentro de un bloque try catch creamos un objeto de la clase OutputStreamWriter y le pasamos el dato que devuelve la función openFileOutput (esta función recibe el nombre del archivo de texto a crear):

        boton1.setOnClickListener {
            try {
                val archivo = OutputStreamWriter(openFileOutput("notas.txt", Activity.MODE_PRIVATE))

Grabamos en el archivo de texto el contenido del et1, confirmamos la grabación llamando al método flush y finalmente cerramos el archivo de texto creado:

                archivo.write(et1.text.toString())
                archivo.flush()
                archivo.close()
            } catch (e: IOException) {
            }

Finalizamos el programa mostrando un mensaje que los datos fueron grabados:

            Toast.makeText(this, "Los datos fueron grabados",Toast.LENGTH_SHORT).show()
            finish()

Por otro lado cada vez que se inicia el programa verificamos si existe el archivo de texto "notas.txt" llamando al método fileList() que nos retorna un objeto de la clase List con todos los archivos de texto existentes en la aplicación, y a partir de esta lista llamamos al método contains que devuelve verdadero si existe el nombre de archivo que le pasamos como referencia:

        if (fileList().contains("notas.txt")) {

En el caso que exista el archivo procedemos a abrirlo para leer creando un objeto de la clase InputStreamReader:

            try {
                val archivo = InputStreamReader(openFileInput("notas.txt"))

Creamos un objeto de la clase BufferedReader para hacer más eficiente la lectura del archivo:

                val br = BufferedReader(archivo)

Luego dentro de una estructura repetitiva procedemos a leer cada línea del archivo de texto y guardar los datos en memoria en un objeto de la clase StringBulder:

                var linea = br.readLine()
                val todo = StringBuilder()
                while (linea != null) {
                    todo.append(linea + "\n")
                    linea = br.readLine()
                }
                br.close()
                archivo.close()

Mostramos los datos recuperados del archivo en el EditText:

                et1.setText(todo)
            } catch (e: IOException) {
            }

Cada vez que ejecutemos el programa veremos las últimas notas guardadas:

Archivos de texto memoria interna

Este proyecto lo puede descargar en un zip desde este enlace: proyecto016.zip

Problema 2:

Confeccionar un programa para administrar un calendario de actividades diarias. Los nombres de archivos corresponderán a las fechas que ingresamos. Luego cuando consultamos una fecha verificamos si hay un archivo de texto que coincida con dicha fecha.

Crear un proyecto en Android Studio y definir como nombre: Proyecto017.

La interfaz visual a crear será la siguiente:

Archivos de texto memoria interna

Es decir disponemos un "TextView" donde dice fecha. Un EditText de tipo "Date" donde se carga la fecha. Luego otro EditText de tipo "Multiline Text" y finalmente dos botones:

  TextView (ID="tv1" text="Fecha")
  EditText de tipo "Date" (ID="et1", hint="Ingrese fecha")
  Button (text="Grabar", ID="boton1")
  Button (text="Recuperar" ID="boton2")
  EditText de tipo "Multiline Text" (id="et2", background="#ffff00")

El código fuente de la aplicación:

package com.tutorialesprogramacionya.proyecto017

import android.app.Activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.io.OutputStreamWriter

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val et1=findViewById<EditText>(R.id.et1)
        val et2=findViewById<EditText>(R.id.et2)
        val boton1=findViewById<Button>(R.id.boton1)
        val boton2=findViewById<Button>(R.id.boton2)
        boton1.setOnClickListener {
            val nomarchivo = et1.text.toString().replace('/','-')
            try {
                val archivo = OutputStreamWriter(openFileOutput(nomarchivo, Activity.MODE_PRIVATE))
                archivo.write(et2.text.toString())
                archivo.flush()
                archivo.close()
            } catch (e: IOException) {
            }
            Toast.makeText(this, "Los datos fueron grabados", Toast.LENGTH_SHORT).show()
            et1.setText("")
            et2.setText("")
        }


        boton2.setOnClickListener {
            var nomarchivo = et1.text.toString().replace('/', '-')
            if (fileList().contains(nomarchivo)) {
                try {
                    val archivo = InputStreamReader(openFileInput(nomarchivo))
                    val br = BufferedReader(archivo)
                    var linea = br.readLine()
                    val todo = StringBuilder()
                    while (linea != null) {
                        todo.append(linea + "\n")
                        linea = br.readLine()
                    }
                    br.close()
                    archivo.close()
                    et2.setText(todo)
                } catch (e: IOException) {
                }
            } else {
                Toast.makeText(this, "No hay datos grabados para dicha fecha", Toast.LENGTH_LONG).show()
                et2.setText("")
            }
        }
    }
}

La función lambda que se ejecuta cuando presionamos el botón 1 tiene primero que extraer la fecha ingresada en el primer EditText y remplazar las barras de la fecha por guiones ya que no se puede utilizar este caracter dentro de un nombre de archivo en Android:

        boton1.setOnClickListener {
            val nomarchivo = et1.text.toString().replace('/','-')

Creamos un objeto de la clase OutputStreamWriter y al constructor de dicha clase le enviamos el dato que retorna el método openFileOutput propio de la clase AppCompatActivity que le pasamos como parámetro el nombre del archivo de texto y el modo de apertura.

            try {
                val archivo = OutputStreamWriter(openFileOutput(nomarchivo, Activity.MODE_PRIVATE))

Seguidamente si el archivo se creó correctamente procedemos a llamar al método write y le pasamos el String a grabar, en este caso extraemos los datos del EditText:

                archivo.write(et2.text.toString())

Luego de grabar con el método write llamamos al método flush para que vuelque todos los datos que pueden haber quedado en el buffer y procedemos al cerrado del archivo:

                archivo.flush()
                archivo.close()

Cada vez que se graba un dato se genera un archivo de texto para dicha fecha, si ya había un archivo con el mismo nombre (es decir la misma fecha) se pisa el anterior.

Para recuperar los datos de una determinada fecha se ejecuta la función lambda que le pasamos al botón 2:

        boton2.setOnClickListener {
            var nomarchivo = et1.text.toString().replace('/', '-')
            if (fileList().contains(nomarchivo)) {
                try {
                    val archivo = InputStreamReader(openFileInput(nomarchivo))
                    val br = BufferedReader(archivo)
                    var linea = br.readLine()
                    val todo = StringBuilder()
                    while (linea != null) {
                        todo.append(linea + "\n")
                        linea = br.readLine()
                    }
                    br.close()
                    archivo.close()
                    et2.setText(todo)
                } catch (e: IOException) {
                }

            } else {
                Toast.makeText(this, "No hay datos grabados para dicha fecha", Toast.LENGTH_LONG).show()
                et2.setText("")
            }
        }

Lo primero que hacemos es recuperar del EditText la fecha que ingresó el operador para buscar y remplazamos las barras por guiones (recordemos que grabamos guiones en la carga ya que la barra de una fecha no es un caracter válido en un archivo en Android)::

            var nomarchivo = et1.text.toString().replace('/', '-')

Verificamos si existe un archivo con dicha fecha:

            if (fileList().contains(nomarchivo)) {

Si existe el archivo procedemos a abrirlo, leerlo y cargar el et2 con los datos del archivo:

                try {
                    val archivo = InputStreamReader(openFileInput(nomarchivo))
                    val br = BufferedReader(archivo)
                    var linea = br.readLine()
                    val todo = StringBuilder()
                    while (linea != null) {
                        todo.append(linea + "\n")
                        linea = br.readLine()
                    }
                    br.close()
                    archivo.close()
                    et2.setText(todo)
                } catch (e: IOException) {
                }

La interfaz visual en tiempo de ejecución debe ser similar a esta:

Archivos de texto memoria interna

Este proyecto lo puede descargar en un zip desde este enlace: proyecto017.zip