7.4.-Lectura/Escritura Archivos
7.4 Lectura y escritura de archivos¶
En 7.3 aprendimos a representar rutas con File y a consultar información sobre ficheros y carpetas. El siguiente paso natural es trabajar con el contenido de esos ficheros: leerlo, procesarlo, modificarlo o guardarlo.
Este tema conecta directamente con los criterios del
RA5relacionados con:
- d) usar ficheros para almacenar y recuperar información.
- e) crear programas que utilicen distintos métodos de acceso al contenido de los ficheros.
Qué vas a aprender en este tema
- Diferenciar lectura y escritura de archivos.
- Entender la diferencia entre ficheros de texto y binarios.
- Reconocer operaciones habituales de lectura y escritura en Kotlin.
- Aplicar buenas prácticas básicas al trabajar con archivos.
1. ¿Por qué leer y escribir archivos?¶
Guardar datos en memoria no basta cuando queremos que la información permanezca entre distintas ejecuciones del programa. Por eso los ficheros son tan importantes: permiten conservar datos, compartirlos con otros programas y recuperarlos más adelante.
Algunos ejemplos habituales:
- guardar notas del alumnado;
- registrar eventos o errores;
- cargar configuraciones al arrancar;
- exportar resultados a un informe;
- almacenar datos para volver a usarlos en otro momento.
Cuando trabajamos con archivos, normalmente realizamos dos tipos de operación:
- lectura: obtener información desde un fichero hacia el programa;
- escritura: enviar información desde el programa hacia un fichero.
2. Texto y binario¶
Antes de leer o escribir, conviene distinguir dos grandes formas de almacenar información.
2.1. Ficheros de texto¶
En un fichero de texto la información se representa como caracteres. Suelen poder abrirse con un editor de texto y resultan cómodos para:
- configuraciones;
- listados;
- archivos CSV;
- logs;
- informes.
Ejemplo de contenido textual:
2.2. Ficheros binarios¶
En un fichero binario la información se almacena como bytes, no como texto legible directamente. Son habituales en:
- imágenes;
- audio y vídeo;
- documentos ofimáticos;
- datos serializados;
- estructuras compactas de datos.
Idea clave
Texto y binario no son “mejor” o “peor”. Cada formato responde a necesidades distintas.
3. Acceso secuencial¶
En muchos programas, el contenido de un fichero se procesa en orden, desde el principio hasta el final. Esto se llama acceso secuencial.
Es el modelo más habitual en esta unidad y se parece bastante a lo que ya hacíamos con la consola:
- leemos una línea;
- o escribimos un dato detrás de otro;
- sin “saltar” constantemente a posiciones intermedias.
Acceso secuencial
Consiste en procesar los datos en el mismo orden en que aparecen almacenados en el fichero.
4. Leer ficheros de texto¶
Kotlin ofrece varias formas sencillas de leer ficheros de texto a partir de java.io.File.
4.1. Leer todo el contenido¶
Si el fichero no es muy grande, podemos leerlo completo con readText():
import java.io.File
fun main() {
val contenido = File("datos/notas.txt").readText()
println(contenido)
}
Esta opción es cómoda, pero no siempre conviene si el archivo es muy grande.
4.2. Leer línea a línea¶
Si nos interesa trabajar por líneas, podemos usar readLines():
import java.io.File
fun main() {
val lineas = File("datos/notas.txt").readLines()
for (linea in lineas) {
println(linea)
}
}
4.3. Procesar de forma más eficiente¶
Cuando el fichero crece, resulta útil useLines(), porque permite procesar líneas sin cargar todo el contenido de golpe:
import java.io.File
fun main() {
File("datos/notas.txt").useLines { lineas ->
lineas.forEach { println(it) }
}
}
Cuándo usar cada una
readText()si quieres todo el contenido como una única cadena.readLines()si quieres una lista de líneas.useLines()si el archivo puede ser grande o quieres procesarlo de forma más eficiente.
5. Escribir ficheros de texto¶
Kotlin también facilita mucho la escritura en archivos de texto.
5.1. Sobrescribir contenido¶
writeText() escribe el contenido indicado y, si el fichero ya existe, reemplaza lo que hubiera antes.
5.2. Añadir contenido al final¶
Si no quieres borrar lo anterior, puedes usar appendText():
5.3. Escritura con bufferedWriter¶
Otra opción es usar un escritor con buffer y use() para asegurar el cierre correcto:
import java.io.File
fun main() {
File("salida.txt").bufferedWriter().use { writer ->
writer.write("Primera línea\n")
writer.write("Segunda línea\n")
}
}
Muy importante
writeText() sobrescribe el contenido existente. Si necesitas conservar lo anterior, usa appendText() o un modo de escritura equivalente.
6. Leer y escribir no es lo mismo¶
Cuando trabajamos con un fichero, es importante tener claro qué operación estamos realizando en cada momento.
- Leer significa interpretar datos que ya existen.
- Escribir significa generar o modificar datos dentro del fichero.
Esto parece obvio, pero tiene consecuencias didácticas importantes:
- al leer, debes saber qué formato esperas;
- al escribir, debes decidir cómo vas a organizar la información;
- y ambas partes deben ser coherentes entre sí.
Por ejemplo, si escribes varias notas separadas por comas, luego tendrás que leerlas respetando ese mismo formato.
7. Errores frecuentes al trabajar con texto¶
Cuando se empieza a trabajar con archivos, aparecen varios errores típicos:
- intentar leer un fichero que no existe;
- no comprobar si la ruta es correcta;
- sobrescribir datos sin querer;
- no respetar el formato esperado del archivo;
- suponer que el contenido siempre será válido;
- cargar en memoria ficheros más grandes de lo necesario.
Error muy común
Si escribes datos en un formato y después intentas leerlos con otra lógica distinta, el programa fallará o interpretará mal la información.
8. Introducción a los ficheros binarios¶
Aunque en clase trabajaremos mucho con texto, también existen situaciones en las que interesa usar binario.
En Java y Kotlin podemos apoyarnos en clases como:
DataOutputStreampara escribir datos binarios;DataInputStreampara leerlos.
import java.io.DataInputStream
import java.io.DataOutputStream
import java.io.FileInputStream
import java.io.FileOutputStream
fun main() {
DataOutputStream(FileOutputStream("datos.bin")).use { salida ->
salida.writeInt(25)
salida.writeBoolean(true)
}
DataInputStream(FileInputStream("datos.bin")).use { entrada ->
val numero = entrada.readInt()
val activo = entrada.readBoolean()
println("Número: $numero")
println("Activo: $activo")
}
}
8.1. La regla clave del binario¶
Cuando se trabaja con binario, los datos deben leerse en el mismo orden y con los mismos tipos con los que se escribieron.
Si escribes:
- un
Int - un
Boolean
después tendrás que leer:
- un
Int - un
Boolean
en ese mismo orden.
Regla esencial
En binario, cambiar el orden o el tipo de lectura rompe la interpretación de los datos.
9. Ejemplo integrador con fichero de texto¶
El siguiente ejemplo combina varias ideas del tema:
import java.io.File
fun main() {
val fichero = File("pedidos.txt")
fichero.appendText("Portátil,2\n")
fichero.appendText("Ratón,5\n")
val lineas = fichero.readLines()
println("Contenido del fichero:")
for (linea in lineas) {
println(linea)
}
}
Este ejemplo:
- escribe datos en un fichero;
- conserva el contenido previo usando
appendText(); - y vuelve a leerlo para mostrarlo por consola.
10. Relación con U7.4.1¶
Este tema ofrece la visión general de la lectura y escritura de archivos. En 7.4.1 profundizaremos en el caso más habitual en el aula: los ficheros de texto, con más detalle sobre:
readText(),readLines()yuseLines();writeText()yappendText();- caracteres especiales como el salto de línea;
- y pequeños casos prácticos de uso.
11. Buenas prácticas básicas¶
Cuando trabajes con archivos, intenta seguir estas recomendaciones:
- usa rutas relativas cuando sea posible;
- comprueba si el fichero existe antes de leerlo;
- elige bien entre sobrescribir y añadir contenido;
- usa
use()o funciones de alto nivel que gestionen bien los recursos; - mantén coherencia entre cómo escribes y cómo lees;
- y separa el trabajo con archivos de la lógica principal del programa cuando el proyecto crezca.
12. Resumen¶
En este tema has visto que:
- leer y escribir archivos permite conservar información entre ejecuciones;
- los ficheros pueden ser de texto o binarios;
- el acceso secuencial es el modelo más habitual en esta unidad;
- Kotlin facilita la lectura con
readText(),readLines()yuseLines(); - y facilita la escritura con
writeText(),appendText()y escritores con buffer.
Con esta base ya puedes empezar a construir programas que no solo procesen datos en memoria, sino que también los guarden y los recuperen de forma persistente.