Almacenamiento de datos en un archivo de texto en almacenamiento externo (tarjeta SD)¶
En el apartado anterior se ha visto cómo crear y leer un archivo de texto en la memoria interna de un dispositivo Android.
En determinadas situaciones puede resultar útil almacenar los datos en el almacenamiento externo (comúnmente asociado a una tarjeta SD), ya sea por:
- Mayor capacidad de almacenamiento.
- Posibilidad de compartir archivos con otros dispositivos o aplicaciones.
- Persistencia más allá del ciclo interno de la app.
Info
No todos los dispositivos Android disponen de tarjeta SD física.
En la práctica actual, el término almacenamiento externo suele referirse al directorio externo privado de la aplicación, accesible mediante getExternalFilesDir().
Este enfoque no requiere permisos especiales en versiones modernas de Android y es el recomendado con fines didácticos y de compatibilidad.
Objetivo del ejemplo¶
La aplicación permitirá:
- Introducir el nombre de un archivo.
- Escribir texto libre en un campo multilínea.
- Guardar el contenido en un archivo de texto en el almacenamiento externo.
- Recuperar el contenido del archivo y mostrarlo en pantalla.
Diseño de la interfaz¶
La interfaz estará compuesta por:
- Un
EditTextde texto simple para el nombre del archivo. - Un
EditTextmultilínea para el contenido. - Un botón para grabar el archivo.
- Un botón para recuperar el contenido.
activity_main.xml¶
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<EditText
android:id="@+id/et1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="Ingrese nombre del archivo"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<EditText
android:id="@+id/et2"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#FF0000"
android:gravity="top|start"
android:inputType="textMultiLine"
app:layout_constraintTop_toBottomOf="@id/et1"
app:layout_constraintBottom_toTopOf="@id/boton1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:padding="8dp"/>
<Button
android:id="@+id/boton1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Grabar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<Button
android:id="@+id/boton2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Recuperar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Permisos en Android¶
En versiones antiguas de Android era necesario declarar:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
⚠️ Actualmente NO es necesario si se utiliza:
getExternalFilesDir(null)
Este método accede a un directorio externo privado de la aplicación, seguro y compatible con Scoped Storage.
Código de la aplicación¶
MainActivity.kt¶
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import java.io.*
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)
// Guardar archivo
boton1.setOnClickListener {
try {
val directorio = getExternalFilesDir(null)
val file = File(directorio, et1.text.toString())
val osw = OutputStreamWriter(FileOutputStream(file))
osw.write(et2.text.toString())
osw.flush()
osw.close()
Toast.makeText(this, "Datos grabados correctamente", Toast.LENGTH_SHORT).show()
et1.setText("")
et2.setText("")
} catch (e: IOException) {
Toast.makeText(this, "No se pudo grabar el archivo", Toast.LENGTH_SHORT).show()
}
}
// Leer archivo
boton2.setOnClickListener {
try {
val directorio = getExternalFilesDir(null)
val file = File(directorio, et1.text.toString())
val fIn = FileInputStream(file)
val reader = BufferedReader(InputStreamReader(fIn))
val contenido = StringBuilder()
var linea = reader.readLine()
while (linea != null) {
contenido.append(linea).append("\n")
linea = reader.readLine()
}
reader.close()
et2.setText(contenido.toString())
} catch (e: IOException) {
Toast.makeText(this, "No se pudo leer el archivo", Toast.LENGTH_SHORT).show()
}
}
}
}
Funcionamiento interno¶
getExternalFilesDir(null)devuelve el directorio externo privado de la app.-
Los archivos almacenados:
- Son accesibles por el usuario (vía explorador de archivos).
- Se eliminan automáticamente al desinstalar la app.
- No se requieren permisos en tiempo de ejecución.
Ventajas y limitaciones¶
Ventajas¶
- Mayor capacidad que la memoria interna.
- Archivos accesibles desde fuera de la app.
- Compatible con versiones modernas de Android.
Limitaciones¶
- No es adecuado para datos sensibles.
- No estructurado.
- No reactivo.
Actividad¶
- AC603. Realiza el ejemplo en Compose, realiza una investigación para poder replicarlo.