Fecha y hora actual: Lunes 23 Sep 2019 11:51
Índice del Foro

Foros de programación informática, diseño gráfico y Web

En esta comunidad intentaremos dar soporte de programación a todos los niveles, desde principiantes a profesionales de la informática, desarrollo de programas, programación web y mucho más.

Lección 101: Lectura/Escritura de archivos de texto plano

Responder al Tema

Índice del Foro > Programación en general > Lección 101: Lectura/Escritura de archivos de texto plano

Autor Mensaje
Kyshuo Ayame
Moderador Global


Registrado: 07 Ene 2011
Mensajes: 1044

Mensaje Publicado: Sábado 26 Oct 2013 03:04

Título del mensaje: Lección 101: Lectura/Escritura de archivos de texto plano

Responder citando

Antes de continuar con componentes de Swing veremos el uso de archivos de texto plano para comenzar a trabajar en la persistencia de nuestros programas. En este ejemplo veremos un programa sencillo que permitirá leer el contenido de un archivo de texto plano ya creado y también guardar texto en un archivo nuevo.

Visualmente la aplicación tendrá esta interfaz:



Nada complicado a estas alturas. El botón Mostrar mostrará en el área de texto el contenido de un archivo llamado archivoEntrada.txt guardado en algún lugar predefinido de nuestro equipo. El botón Guardar creará un archivo de texto llamado archivoSalida.txt con el contenido del área de texto en el mismo lugar donde está el archivo anterior.

Haremos todo en la clase principal de nuestro sistema para no complicar las cosas y centrarnos en la lectura y escritura de archivos. Podría haber obviado la interfaz gráfica y hacer todo por consola, pero como es una GUI tan simple no creo que les genere mayores dificultades.

Creamos entonces un nuevo proyecto con el nombre que quieran y en él crean su clase principal cuyo código inicial será así:

Código:
  1. public class EntradaSalida implements ActionListener{
  2. JFrame ventana;
  3. JPanel panelPrincipal;
  4. JScrollPane panelArea;
  5. JTextArea areaTexto;
  6. JButton botonGuardar, botonMostrar;
  7.  
  8. public EntradaSalida(){
  9. ventana= new JFrame("Lectura escritura TXT");
  10. panelPrincipal= new JPanel();
  11.  
  12. areaTexto= new JTextArea(25,50);
  13. panelArea= new JScrollPane(areaTexto);
  14. panelPrincipal.add(panelArea);
  15.  
  16. ventana.setVisible(true);
  17. ventana.setContentPane(panelPrincipal);
  18.  
  19. botonMostrar= new JButton("Mostrar");
  20. botonGuardar= new JButton("Guardar");
  21. botonMostrar.addActionListener(this);
  22. botonGuardar.addActionListener(this);
  23.  
  24. panelPrincipal.add(botonMostrar);
  25. panelPrincipal.add(botonGuardar);
  26.  
  27. ventana.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  28. ventana.pack();
  29. ventana.setLocationRelativeTo(null);
  30. }


Implementamos ActionListener para manejar los eventos de los dos botones y así diferenciar si queremos leer desde un archivo o escribir en uno. Lo único que hacemos en el constructor es crear la ventana y asignar a la propia clase EntradaSalida como escucha de eventos de ambos botones.

===============================================

Lectura de un archivo de texto plano

Ahora crearemos un procedimiento llamado mostrarTexto que será el encargado de leer el archivo de entrada para desplegar su texto en el área de salida. El archivo tiene que estar previamente creado, por tanto abrimos un editor de texto plano como el Bloc de Notas en Windows o cualquier otro en Linux y escribimos en él lo que se nos de la gana; por ejemplo:



Guardamos el archivo donde más nos guste teniendo en cuenta que tendremos que conocer su ruta para acceder a él. En mi caso lo guardé en C:\ con el nombre archivoEntrada.txt.
Ahora creamos el procedimiento:

Código:
  1. public void mostrarTexto(){
  2. File archivo= new File("C:/archivoEntrada.txt");
  3. try{
  4. areaTexto.setText(""); //Limpiamos el area de texto.
  5. FileReader lectorArchivo= new FileReader(archivo);
  6. BufferedReader lectorFlujo= new BufferedReader(lectorArchivo);
  7.  
  8. String lineaTexto= lectorFlujo.readLine(); //Leo la primera línea.
  9. while(lineaTexto!=null){
  10. areaTexto.append(lineaTexto+"\n");
  11. lineaTexto= lectorFlujo.readLine();
  12. }
  13. lectorFlujo.close();
  14. areaTexto.setText(e.getMessage());
  15. }catch(IOException e){
  16. areaTexto.setText(e.getMessage());
  17. }
  18. }


Veamos línea por línea qué es lo que hay allí. Lo primero es crear un objeto de la clase File, la cual está disponible en el paquete java.io. Verán que el constructor de esta clase solicita un String con la ruta absoluta del archivo que vamos a usar, en mi caso como el archivo se llama archivoEntrada.txt y está en C:\ escribo C:/archivoEntrada.txt. Noten que en Windows la ruta sería C:\archivoEntrada.txt pero yo usé la barra inclinada normal (/). Esto se debe a que la barra inversa (\) es el carácter de escape en literales String de Java; si quiero escribir la ruta de un archivo con esa barra tengo que usarla doble ya que el carácter de escape \\ en un String imprime la barra \.
¿Por qué sirve tanto usar \\ como /? Pues porque la JVM no hace distinción entre ellas para las rutas de archivo. Sin embargo no es lo más recomendable escribir las rutas de archivos de esta manera. Ya veremos por qué y cómo hacerlo correctamente.

Siempre al trabajar con archivos podremos tener distintos tipos de excepciones por tanto incluimos nuestro código dentro de un bloque try-catch. Lo siguiente que hago es limpiar el área de texto por si tuviera algo escrito en ella.

Tenemos, mediante el objeto de la clase File llamado archivo, una referencia al archivo en el disco duro. Sin embargo la clase File es muy genérica y sirve para trabajar con muchos tipos de archivo, es decir, no hace diferencia se es un archivo de texto, una carpeta (directorio), o lo que sea. Para trabajar más específicamente con archivos de texto, como es el caso, necesitamos envolver nuestra referencia con un objeto de la clase FileReader (lector de archivo) también de java.io, con lo cual estamos diciendo que vamos a LEER el archivo. En este paso, si el archivo no existe en la ruta especificada se nos lanzará una excepción FileNotFoundException (excepción de archivo no encotrado), también disponible en el paquete java.io.

Ahora bien, leer un archivo es una operación también bastante general porque no es lo mismo leer texto plano que texto formateado (por ejemplo Word) o una planilla de cálculo (por ejemplo Excel) o un archivo específicamente creado para un programa particular. En nuestro caso como queremos leer texto simple tenemos que tratarlo como un flujo de datos que fácilmente puede ser tratado luego como String. Para esto envolvemos nuestro lector de archivos como lector de flujo mediante la clase BufferedReader (del mismo paquete) teniendo así el objeto lectorFlujo.

Un objeto BufferedReader nos permite leer línea a línea del archivo de texto y obtener el contenido como String mediante la operación readLine. Cuando se ha llegado al final del archivo, o bien, si este está vacío, readLine retorna null. De este modo leemos la primera línea así:

Código:
  1. String lineaTexto= lectorFlujo.readLine();


Esta operación lanza una excepción IOException (del mismo paquete) si existe algún error al momento de leer el archivo.

El while a continuación itera mientras la lectura no sea nula, lo cual implicaría haber llegado al final del archivo. En cada iteración agregamos el texto leído al área de texto.

Finalmente cerramos el archivo mediante la operación close. Esto es muy importante porque si no lo hacemos el Sistema Operativo tendrá marcado al archivo como en uso lo cual implica que si otro programa necesita modificarlo o eliminarlo no podrá. Es importante liberar siempre los recursos que usamos.

===============================================

Escritura de un archivo de texto plano:

La escritura de un nuevo archivo es muy similar a la lectura. Crearemos para este ejemplo un procedimiento llamado guardarTexto que será el encargado de crear un nuevo archivo y escribir en él lo que hay en el área de texto:

Código:
  1. public void guardarTexto(){
  2. File archivoTexto= new File("C:/archivoSalida.txt");
  3.  
  4. try{
  5. if(!archivoTexto.exists()){
  6. archivoTexto.createNewFile();
  7. }
  8.  
  9. FileWriter escritorArchivo= new FileWriter(archivoTexto);
  10. BufferedWriter escritorFlujo= new BufferedWriter(escritorArchivo);
  11. PrintWriter impresorArchivo= new PrintWriter(escritorFlujo);
  12.  
  13. impresorArchivo.println(areaTexto.getText());
  14. impresorArchivo.close();
  15. }catch(IOException e){
  16. areaTexto.setText(e.getMessage());
  17. }
  18. }


Nuevamente lo primero que hacemos es crear un objeto File pasando la ruta absoluta de un archivo escribiéndola en forma de String. En este caso como quiero crear un nuevo archivo en C:\ llamado archivoSalida.txt escribo C:/archivoSalida.txt.

Dado que nuestras operaciones pueden lanzar excepciones del tipo IOException debemos colocar el resto de nuestro código dentro de un bloque try-catch. Verán que lo primero que hago es verificar si el archivo existe utilizando la operación booleana exists de File. Esta operación retorna true si el archivo existe en la ruta especificada y false si no existe allí o bien si la ruta pasada como argumento al crear File es una ruta errónea.

Si no existe el archivo entonces lo creamos mediante la operación createNewFile. Para que esta operación funcione, la ruta antes del nombre del archivo debe ser válida. Por ejemplo si yo quería crear el archivo en una ruta C:\Ejemplo\archivoSalida.txt pero dentro de C:\ no existe ninguna carpeta llamada Ejemplo entonces no se podrá crear el archivo. En este caso se lanza una excepción IOException. Para crear carpetas en vez de usar createNewFile se utiliza mkdir y mkdirs, las cuales veremos más adelante.

Creado entonces el nuevo archivo ahora debemos escribir en él. Para esto tenemos que envolver nuestro objeto File dentro de un objeto FileWirter (escritor de archivo) tal como lo hago al instanciar al objeto escritorArchivo. Ahora bien, como lo que nosotros queremos es escribir archivos de texto plano nos facilita la vida escribirlos como flujos de información para lo cual envolvemos al escritor dentro de un objeto BufferedWriter. Luego, envolvemos al BufferedWriter dentro de un objeto PrintWriter ya que nos permite tratar a los flujos como Strings, así que la final de cuentas terminamos trabajando con el objeto impresorArchivo.

NOTA: Todas las clases nombradas aquí son del paquete java.io.

La clase PrintWriter tiene operaciones para escribir todo tipo de datos, tanto Strings como otros tipos primitivos y objetos. Nosotros usamos la operación println que recibe un String para escribir texto en el archivo. Luego de eso lo cerramos mediante la operación close.

===============================================

Completando el sistema:

Tenemos entonces el constructor de nuestra clase, un procedimiento para escribir en un archivo y otro para leer desde uno. Nos falta únicamente dar funcionalidad a los botones y escribir el procedimiento main; dicho de otra forma nos falta escribir el método de actionPerformed y el de main:

Código:
  1. @Override
  2. public void actionPerformed(ActionEvent e) {
  3. if(e.getSource().equals(botonMostrar)){
  4. mostrarTexto();
  5. }else if(e.getSource().equals(botonGuardar)){
  6. guardarTexto();
  7. }
  8. }
  9.  
  10. public static void main(String[] args) {
  11. EntradaSalida app= new EntradaSalida();
  12. }


Con eso queda completa nuestra clase EntradaSalida y podemos ejecutar nuestro pequeño sistema. Como habrán visto esto ha sido sumamente sencillo. Si bien no me he detenido a explicar qué son flujos y por qué envolvemos un objeto dentro de otro, conque ustedes tengan el procedimiento de lectura y escritura presente podrán hacer cosas muy complejas, como veremos más adelante.

===============================================

Problema con las rutas absolutas en código:

En este ejemplo, dado que es el primero acerca de este tema, hemos usado rutas absolutas para los archivos que queremos usar. Esto quiere decir que hemos especificado el lugar exacto a encontrar y/o crear archivos dentro del propio código fuente y, aunque ha funcionado bien, no es una buena práctica por los siguientes motivos:

  • El usuario no tiene posibilidad ninguna de elegir donde buscar o crear archivos y queda sujeto a lo que el programador escribió en el código fuente, le guste o no.
  • Si queremos distribuir nuestra aplicación, por ejemplo, mediante un JAR, solo usuarios que tengan en su equipo una unidad C podrán usarla. Si por ejemplo, al instalar el sistema operativo, se nombró a la unidad con la letra D u otra distinta y por tanto no existe una unidad C pues nuestro programa no encontrará la ruta y no podrá hacer nada.
  • El programa del ejemplo solo funcionará en Windows ya que solo en estos sistemas es posible encontrar una unidad C. En sistemas Linux el sistema de archivos es totalmente distinto y no encontraremos de ninguna manera algo llamado C:\ ya que en estos sistemas todo parte de un único directorio raíz denominado por la barra inclinada /. Esto hace que nuestro programa Java ya no sea multiplataforma porque no habrá manera de que funcione en Linux, Solaris o Mac, sino que solo funcionará en Windows.


La solución a esto es NO usar rutas absolutas en literales String, sino obtenerlas a partir del sistema en que estamos, cosa que es muy sencilla pero que veremos luego.

===============================================

Multi catch:

Esto podría haberlo nombrado cuando introduje excepciones, sin embargo preferí aplazarlo para que trabajaran a la antigua con los bloques try-catch. ¿Qué quiero decir con esto? Pues que lo que les voy a enseñar aquí es algo totalmente nuevo en Java, incluso yo lo aprendí con una sugerencia de NetBeans (quizá alguno de ustedes también).

Si se fijan en el bloque try-catch del procedimiento mostrarTexto tenemos dos catch que hacen exactamente lo mismo:

Código:
  1. try{
  2. . . .
  3. . . .
  4. areaTexto.setText(e.getMessage());
  5. }catch(IOException e){
  6. areaTexto.setText(e.getMessage());
  7. }


Desde la versión 7 de Java podemos hacer que un mismo catch capture varios tipos distintos de excepciones simplmente separándolos por una barra vertical | tal como el OR exclusivo (justamente eso es). Entonces el código anterior queda así:

Código:
  1. try{
  2. . . .
  3. }catch(FileNotFoundExcepcion | IOException e){
  4. areaTexto.setText(e.getMessage());
  5. }


Por supuesto esto funciona para más de dos tipos de excepciones y únicamente tiene sentido si lo que tenemos que hacer es lo mismo indistintamente del tipo capturado. Algunas veces esto no se cumple por lo cual usamos diferentes catch para los distintos tipos de excepciones a capturar y listo.

Muchas veces las sugerencias de NetBeans aplican técnicas nuevas disponibles en las actualizaciones de Java. Por esto es importante tener el JDK actualizado tanto como sea posible.

===============================================

Esto ha sido todo por ahora. Hasta la próxima lección.

Volver arriba
Ver perfil del usuario Enviar mensaje privado
Tesis
Administrador


Registrado: 04 Mar 2007
Mensajes: 3227
Ubicación: Valencia - España

Mensaje Publicado: Sábado 26 Oct 2013 20:00

Título del mensaje: Re: Lección 101: Lectura/Escritura de archivos de texto plan

Responder citando

Fantástico amigo !!!!!
Pocos cursos llegan a las 100 lecciones y mucho menos superarlas.


Enhorabuena por el excelente trabajo y la calidad de los contenidos.



Saludos.


Normas del foro
Aprende a postear correctamente usando las etiquetas
Volver arriba
Ver perfil del usuario Enviar mensaje privado
Konguito
Usuario Iniciado


Registrado: 04 Abr 2013
Mensajes: 14

Mensaje Publicado: Sábado 26 Oct 2013 23:12

Título del mensaje: Re: Lección 101: Lectura/Escritura de archivos de texto plan

Responder citando

Aplauso Aplauso Gracias!! Aplauso Aplauso

Volver arriba
Ver perfil del usuario Enviar mensaje privado
xRoki
Usuario Inquieto


Registrado: 22 Ago 2013
Mensajes: 71

Mensaje Publicado: Miércoles 19 Feb 2014 15:58

Título del mensaje: Lección 101: Lectura/Escritura de archivos de texto plano

Responder citando

se me olvido decirte, llevo dos meses que llegue a la leccion 11, y se me olvido agradecerte todo, comence desde 0 y este curso es perfecto. muchisisisisimas gracias por todo.

Volver arriba
Ver perfil del usuario Enviar mensaje privado
Responder al Tema
Mostrar mensajes anteriores:   
Ir a:  
Todas las horas están en GMT + 2 Horas

Temas relacionados

Tema Autor Foros Respuestas Publicado
El foro no contiene ningún mensaje nuevo

necesito ayuda con el algoritmo de dijkstra en ...

mery Python 0 Jueves 13 Dic 2018 18:07 Ver último mensaje
El foro no contiene ningún mensaje nuevo

pasar archivo de texto a excel

harold vasquez Visual Basic y VBA 0 Jueves 06 Abr 2017 19:07 Ver último mensaje
El foro no contiene ningún mensaje nuevo

Insertar por codigo vba, el estilo de texto Rom...

Alonso Visual Basic y VBA 0 Domingo 17 Jul 2016 21:12 Ver último mensaje
El foro no contiene ningún mensaje nuevo

Porque no puedo descargar archivos desde la nube?

reeccom Visual Basic .NET 0 Sábado 28 May 2016 18:08 Ver último mensaje
El foro no contiene ningún mensaje nuevo

Procesar y facturar con archivos .xml mediante ...

Monje_Babuino C, C#, Visual C++ 0 Viernes 04 Mar 2016 16:53 Ver último mensaje
Panel de Control
No puede crear mensajes, No puede responder temas, No puede editar sus mensajes, No puede borrar sus mensajes, No puede votar en encuestas,