Programación

1º DAM/DAW - Curso 2023-2024

User Tools

Site Tools


apuntes:ficheros

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
apuntes:ficheros [2019/02/16 19:49] Santiago Faciapuntes:ficheros [2023/05/28 12:12] (current) – [Files] Santiago Faci
Line 1: Line 1:
 ====== Ficheros ====== ====== Ficheros ======
  
-===== Ficheros de texto =====+===== Tipos de ficheros =====
  
-==== Crear ficheros de texto ====+Desde el punto de vista de un programador solamente distinguiremos entre dos tipos de ficheros:
  
-La manera más cómoda y habitual de crear ficheros de texto es hacerlo línea línea con la clase ''PrintWriter''+  * **Ficheros de texto** cuando el contenido del fichero contenga exclusivamente caracteres de texto (podemos leerlo con un simple editor de texto) 
 + 
 +^ Extensión  ^ Tipo de fichero        | 
 +| .txt       | Fichero de texto plano | 
 +| .xml       | Fichero XML   | 
 +| .json       | Fichero de intercambio de información   | 
 +| .props       | Fichero de propiedades   | 
 +| .conf       | Fichero de configuración   | 
 +| .sql       | Script SQL   | 
 +| .srt       | Fichero de subtítulo   | 
 + 
 +  * **Ficheros binarios** cuando no estén compuestos exclusivamente de texto. Pueden contener imágenes, videos, ficheros, . . . aunque también podemos considerar un fichero binario a un fichero de Microsoft Word en el que sólo hayamos escrito algún texto puesto que, al almacenarse el fichero, el procesador de texto incluye alguna información binaria 
 + 
 +^ Extensión  ^ Tipo de fichero        | 
 +| .pdf       | Fichero PDF | 
 +| .jpg       | Fichero de imagen   | 
 +| .doc, .docx       | Fichero de Microsoft Word   | 
 +| .avi       | Fichero de video   | 
 +| .ppt, .pptx       | Fichero de PowerPoint   | 
 + 
 +A veces, en ficheros binarios, podremos encontrarnos con las extensiones //.bin// o //.dat// para hacer referencia a ficheros que contienen información binaria en un formato que no está ampliamente difundido. Serán simplemente ficheros que una aplicación determinada es capaz de leer/escribir de una forma específica solo definida para dicha aplicación. 
 + 
 +===== System Properties ===== 
 + 
 +En cualquier caso, para el acceso ficheros independientemente del tipo de los mismos, conviene conocer el funcionamiento de las [[https://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html|System Properties]] de las que dispone Java en su API. Éstas permiten acceder a propiedades de la configuración del sistema y, entre otras, podemos encontrarnos con algunas muy interesantes relacionadas con este tema: 
 +  * ''"file.separator"'' Obtiene el caracter, según el S.Operativo, para la separación de las rutas (''/'' ó ''\''). También se puede utilizar la constante ''File.separator'' 
 +  * ''"user.home"'' Obtiene la ruta de la carpeta personal del usuario (que dependerá del S.Operativo en casa caso) 
 +  * ''"user.dir"'' Obtiene la ruta en la que se encuentra actualmente el usuario 
 +  * ''"line.separator"'' Obtiene el caracter que separa las líneas de un fichero de texto (difiere entre Windows/Linux) 
 + 
 +En el caso de que se quiera acceder al valor de alguna de estas propiedades debe hacerse utilizando la llamada al método ''System.getProperty(String)'' 
 + 
 +<code java> 
 +System.out.println("La carpeta de mi usuario es " + System.getProperty("user.home")); 
 +</code>  
 +===== Ficheros de texto ====== 
 + 
 +En esta parte vamos a trabajar con 3 tipos de ficheros de texto:  
 + 
 +  * **Ficheros de texto plano** que contendrán texto //libre// y donde podremos escribir sin respetar ningún tipo de formato 
 +  * **Ficheros de configuración** que contendrán información de configuración para una aplicación. Tienen un formato específico y Java además proporciona una API para trabajar más cómodamente con ellos 
 +  * **Ficheros XML** que contienen información y acompañada de etiquetas que le dan significado. Tienen unas reglas y formato más o menos definido y Java proporciona una API para trabajar con ellos 
 + 
 +Existen más tipos de ficheros de texto también muy extendidos como //.json// y //.csv// pero no serán estudiados en esta parte. 
 +==== Ficheros de texto plano ===== 
 + 
 +Los ficheros de texto son aquellos que únicamente contienen texto, por lo que pueden ser editados directamente con cualquier editor de texto plano (Bloc de Notas, notepad++, . . .). Se podría decir que son aquellos ficheros que podrían ser //leídos// por cualquier persona. Son aquellos que normalmente se almacenan con la extensión //.txt// pero también podríamos incluir los scripts SQL (//.sql//), ficheros de código Java (//.java//), ficheros de configuración (//.ini//, //.props//, //.conf//, . . .), . . . 
 + 
 +También se incluyen en la categoría de ficheros de texto los que además incluyen información adicional (siempre en forma de texto) que permiten interpretar los datos del fichero de una manera u otra, añadiendo más información al mismo. Estos formatos son HTML, XML, JSON, . . . 
 + 
 +En cualquier caso, desde Java siempre se podrán leer/escribir de la misma manera, según veremos a continuación. También veremos como pueden leerse/escribirse utilizando librerías aquellos ficheros de texto plano que contienen formato, como hemos comentado anteriormente, haciendo de esa forma mucho más fácil el trabajo. 
 + 
 +=== Escribir ficheros de texto plano ===
  
 <code java> <code java>
 FileWriter fichero = null; FileWriter fichero = null;
 PrintWriter escritor = null; PrintWriter escritor = null;
-  + 
-try {  +try { 
-    fichero = new FileWriter("archivo.txt"); +  fichero = new FileWriter("archivo.txt"); 
-    escritor = new PrintWriter(fichero) ; +  escritor = new PrintWriter(fichero) ; 
-    escritor.println("Esto es una linea del fichero");+  escritor.println("Esto es una linea del fichero");
 } catch (IOException ioe) { } catch (IOException ioe) {
-    ioe.printStackTrace() ;+  ioe.printStackTrace() ;
 } finally { } finally {
-    if (fichero != null) +if (fichero != null) 
-        try { +  try { 
-            fichero.close(); +    fichero.close(); 
-        } catch (IOException ioe) { . . . }+  } catch (IOException ioe) { . . . 
 +}
 </code> </code>
  
-==== Leer ficheros de texto ===+=== Leer ficheros de texto plano ===
- +
-Para realizar la operación de lectura de un fichero de texto línea a línea utilizaremos la clase ''BufferedReader'', recorriendo el fichero mientras haya líneas en él. +
- +
-En el ejemplo que se muestra, cada línea se muestra por pantalla, pero hay que tener en cuenta que podríamos almacenarlas todas en un solo ''String'' para almacenar su contenido o bien cargarlo en la pantalla para su visualización (y quizás posterior edición).+
  
 <code java> <code java>
Line 36: Line 85:
  
 try { try {
-    buffer = new BufferedReader(new FileReader(new File("archivo.txt"))); +  buffer = new BufferedReader(new FileReader(new File("archivo.txt"))); 
-    String linea = null; +  String linea = null; 
-    while ((linea = buffer.readLine()) != null) +  while ((linea = buffer.readLine()) != null) 
-        System.out.println(linea); +    System.out.println(linea); 
-} catch (FileNotFoundException fnfe) { +} catch (FileNotFoundException fnfe) {  
-    fnfe.printStackTrace(); +  fnfe.printStackTrace(); 
-} catch (IOException ioe) { +} catch (IOException ioe) {  
-    ioe.printStackTrace();+  ioe.printStackTrace(); 
 } finally { } finally {
-    if (buffer != null) +  if (buffer != null) 
-        try { +  try { 
-            buffer.close(); +    buffer.close(); 
-    } catch (IOException ioe) { . . . }+  } catch (IOException ioe) { . . . }
 } }
 </code> </code>
  
-===== Ficheros binarios =====+==== Ficheros de configuración ====
  
-==== Serialización ====+En la API de Java se incluyen librerías para trabajar con los ficheros de configuración. Puesto que todos siguen un mismo patrón, es la librería la que se encarga de acceder al fichero a bajo nivel y el programador sólo tiene que indicar a que propiedad quiere acceder o que propiedad quiere modificar, sin tener que añadir nada de código para leer o escribir el fichero tal y como hemos visto en el punto anterior.
  
-La serialización es el proceso por el que un objeto Java se convierte en una secuencia de bytes, es decir, en un fichero. Es la manera más cómoda y rápida de almacenar en fichero la información de una aplicación Java. Si, por ejemplo, tenemos una serie de objetos como una colección (un ''ArrayList'', por ejemplo) y queremos almacenar toda esa información en un fichero, la forma más sencilla será la de serializar dicho ''ArrayList'', lo que conllevará que se serialice todo su contenido.+Un ejemplo de fichero de configuración de esta librería de java sería el fichero que sigue:
  
-Si más adelante queremos recuperar esa información, podremos deserializar la colección desde el fichero y volver a trabajar con los datos.+<file properties configuracion.props> 
 +# Fichero de configuracion 
 +# Thu Nov 14 10:49:39 CET 2013
  
-Simplemente tendremos que tener en cuenta que las clases que nosotros nos hayamos definido deben implementar el interfaz ''Serializable'' para que pueda ser serializadas en un fichero. Así, si tuvieramos una clase ''Producto''  que queremos que luego sea serializadaharíamos lo siguiente:+user=usuario 
 +password=micontrasena 
 +server=localhost 
 +port=3306 
 +</file> 
 + 
 +=== Escribir ficheros de configuración === 
 + 
 +Así, si queremos generardesde Java, un fichero de configuración como el anterior:
  
 <code java> <code java>
-public class Producto implements Serializable { +. . . 
-    private static final long serialVersionUID 1L+Properties configuracion new Properties()
-    private String nombre+configuracion.setProperty("user", miUsuario)
-    private float precio;+configuracion.setProperty("password", miContrasena); 
 +configuracion.setProperty("server", elServidor); 
 +configuracion.setProperty("port", elPuerto); 
 +try { 
 +  configuracion.store(new FileOutputStream("configuracion.props"),  
 +                                           "Fichero de configuracion"); 
 +} catch (FileNotFoundException fnfe ) {  
 +  fnfe.printStackTrace();  
 +} catch (IOException ioe) {  
 +  ioe.printStackTrace(); 
 +
 +. . . 
 +</code>
  
-    public Producto(String nombre, float precio) { +=== Leer ficheros de configuración ===
-        this.nombre nombre; +
-        this.precio precio; +
-    }+
  
-    public String getNombre() { return nombre; } +A la hora de leerlo, en vez de tener que recorrer todo el fichero como suele ocurrir con los ficheros de texto, simplemente tendremos que cargarlo e indicar de qué propiedad queremos obtener su valor (''getProperty(String)'').
-    public void setNombre(String nombre{ this.nombre = nombre; }+
  
-    public float getPrecio() { return precio } +<code java> 
-    public void setPrecio(float precio{ this.precio precio; }+. . . 
 +Properties configuracion = new Properties()
 +try { 
 +  configuracion.load(new FileInputStream("configuracion.props"))
 +  usuario = configuracion.getProperty("user")
 +  password = configuracion.getProperty("password"); 
 +  servidor configuracion.getProperty("server"); 
 +  puerto = Integer.valueOf(configuration.getProperty("port")); 
 +catch (FileNotFoundException fnfe ) {  
 +  fnfe.printStackTrace(); 
 +} catch (IOException ioe) {  
 +  ioe.printStackTrace();
 } }
 +. . .
 </code> </code>
  
-Las clases Java como ''ArrayList'', ''String'',otras, ya están definidas como ''Serializable'' por lo que no tendremos que preocuparnos por ellas la hora de serializar nuestra colección de productos a un fichero.+Para ambos casos, escribir y leer este tipo de ficheros, hay que tener en cuenta que, al tratarse de ficheros de texto, toda la información se almacena como si de un ''String'' se tratara. Por tantotodos aquellos tipos ''Date'', ''boolean'' o incluso cualquier tipo numérico serán almacenados en formato texto. Así, habrá que tener en cuenta las siguientes consideraciones: 
 + 
 +  * Para el caso de las fechas, deberán ser convertidas a texto cando se quieran escribir nuevamente reconvertidas a ''Date'' cuando se lea el fichero y queramos trabajar con ellas 
 +  * Para el caso de los tipos ''boolean''podemos usar el método ''String.valueOf(boolean)'' para pasarlos a ''String'' cuando queramos escribirlos. En caso de que queramos leer el fichero y pasar el valor a tipo ''boolean'' podremos usar el método ''Boolean.parseBoolean(String)'' 
 +  * Para el caso de los tipos numéricos (''integer'', ''float'', ''double'') es muy sencillo ya que Java los convertirá a ''String'' cuando sea necesario al escribir el fichero. En el caso de que queramos leerlo y convertirlos a su tipo concreto, podremos usar los métodos ''Integer.parseInt(String)'', ''Float.parseFloat(String)'' y ''Double.parseDouble()'', según proceda 
 +==== Ficheros XML ==== 
 + 
 +Los ficheros XML permiten el intercambio de información entre aplicaciones utilizando para ello un fichero de texto plano al que se le pueden añadir etiquetas para darle significado cada uno de los valores que se almacenan. 
 + 
 +Por ejemplo, el siguiente fichero XML podría ser el resultado de volcar una Base de Datos sobre productos de una compañia, de forma que dicha información podría ahora leerse desde otra aplicación e incorporarla. Se puede ver como parte de los datos de dichos productos (sus nombres, precios, . . .) aparece otra información en forma de etiquetas (entre los caracteres ''<'' y ''>'') que permite dar significado a cada dato almacenado en el fichero. Así, podemos saber de qué estamos hablando y a qué corresponde cada valor. 
 + 
 +Obviamente, tal y como ocurría con los ficheros de configuración, toda la información se tiene que pasar a texto para poder crear el fichero y reconvertida a su tipo original cuando se cargue de nuevo. Las mismas consideraciones que hemos tenido en cuenta antes nos servirán ahora (ver [[http://datos.codeandcoke.com/apuntes:ficheros#ficheros_de_configuracion|aqui]]) 
 + 
 +<file xml productos.xml> 
 +<?xml version="1.0" encoding="UTF-8" standalone="no"> 
 +<xml> 
 +<productos> 
 +  <producto> 
 +    <nombre>Cereales</nombre> 
 +    <precio>3.45</precio> 
 +  </producto> 
 +  <producto> 
 +    <nombre>Colacao</nombre> 
 +    <precio>1.45</precio> 
 +  </producto> 
 +  <producto> 
 +    <nombre>Agua mineral</nombre> 
 +    <precio>1.00</precio> 
 +  </producto> 
 +</productos> 
 +</xml> 
 +</file> 
 + 
 +La clase Java que definiría cada uno de los objetos que se representan por el fichero XML anterior, sería la siguiente: 
 + 
 +<file java Producto.java> 
 +public class Producto { 
 +  private String nombre; 
 +  private float precio; 
 +   
 +  public Producto(String nombre, float precio) { 
 +    this.nombre = nombre; 
 +    this.precio = precio; 
 +  } 
 +   
 +  public String getNombre () { return nombre; } 
 +  public void setNombre (String nombre) { this.nombre = nombre; } 
 +   
 +  public float getPrecio () { return precio; } 
 +  public void setPrecio (float precio) { this.precio = precio; } 
 +
 +</file>
  
-=== Serializar objetos ===+=== Escribir ficheros XML ===
  
-Si suponemos que ''listaProductos'' espor ejemplo, una colección de productospodemos serializar el objeto en un fichero llamado ''productos.dat'', de forma que podrá ser recuperado en otra ejecución de la misma ejecuciónhabiendo almacenado así los datos en el disco duro. Es lo que se conoce como persistencia.+Si ahora queremos generar el fichero XML con toda la información de una colección de objetos //Producto//podemos utilizar el siguiente código: 
 + 
 +<code java> 
 +. . . 
 +documento = dom.createDocument(null"xml", null); 
 +Element raiz = document.createElement("productos"); 
 +documento.getDocumentElement().appendChild(raiz); 
 +Element nodoProducto = null , nodoDatos = null ; 
 +Text texto = null; 
 + 
 +for (Producto producto : listaProductos) { 
 +  nodoProducto = documento.createElement("producto"); 
 +  raiz.appendChild(nodoProducto); 
 +  nodoDatos = documento.createElement("nombre"); 
 +  nodoProducto.appendChild(nodoDatos); 
 +  texto = documento.createTextNode(producto.getNombre()); 
 +  nodoDatos.appendChild(texto); 
 +  nodoDatos = documento.createElement("precio"); 
 +  nodoProducto.appendChild(nodoDatos); 
 +  texto = documento.createTextNode(producto.getPrecio()); 
 +  nodoDatos.appendChild(texto); 
 +
 +. . . 
 +</code> 
 + 
 +=== Leer ficheros XML === 
 + 
 +Y si lo que queremos es leer un fichero XML y cargarlo como una colección Java de objetos //Producto//, el ejemplo siguiente muestra un breve ejemplo acerca de cómo acceder a la información de dicho fichero XML. 
 + 
 +<code java> 
 +. . . 
 +NodeList productos = documento.getElementyByTagName("producto"); 
 +for (int i = 0; i < productos.getLength(); i++) { 
 +  Node producto = productos . item ( i ) ; 
 +  Element elemento = ( Element ) producto ; 
 +  System.out.println(elemento.getElementsByTagName("nombre").item(0) 
 +                     .getChildNodes().item(0).getNodeValue()); 
 +  System.out.println(elemento.getElementsByTagName("precio").item(0) 
 +                     .gethildNodes().item(0).getNodeValue()); 
 +
 +. . . 
 +</code> 
 +===== Ficheros binarios ===== 
 + 
 +<file java Producto.java> 
 +public class Producto implements Serializable { 
 +  private static final long serialVersionUID = 1L; 
 +  private String nombre; 
 +  private float precio; 
 + 
 +  public Producto(String nombrefloat precio) { 
 +    this.nombre = nombre; 
 +    this.precio = precio; 
 +  } 
 +   
 +  public String getNombre() { return nombre; } 
 +  public void setNombre(String nombre) { this.nombre = nombre; } 
 +   
 +  public float getPrecio() { return precio ; } 
 +  public void setPrecio(float precio) { this.precio = precio; } 
 +
 +</file> 
 +==== Serialización de objetos ==== 
 + 
 +//Serializar// es el proceso por el cual un objeto en memoria pasa a transformarse en una estructura que pueda ser almacenada en un fichero (persistencia). Al proceso contrario le llamaremos //deserializar//
 + 
 +Hay que tener en cuenta que durante el proceso de serializacióncada objeto se serializa a un fichero, por lo que si queremos almacenar todos los objetos de una aplicación, la idea más conveniente es tener todos éstos en alguna estructura compleja (y por comodidad dinámica) de forma que sea esta estructura la que serialicemos o deserialicemos para guardar o cargar los objetos de una aplicación. Estructuras como ''ArrayList'', ''Set'' ó ''HashMap'' son clases muy utilizadas para trabajar de esta manera 
 + 
 +=== Serializar un objeto ===
  
 <code java> <code java>
Line 91: Line 289:
 ObjectOutputStream serializador = null; ObjectOutputStream serializador = null;
 try { try {
-    serializador = new ObjectOutputStream(new FileOutputStream("productos.dat")); +  serializador = new ObjectOutputStream(new FileOutputStream("archivo.dat")); 
-    serializador.writeObject(listaProductos);+  serializador.writeObject(listaProductos);
 } catch (IOException ioe) {  } catch (IOException ioe) { 
-    . . .+  . . .
 } finally { } finally {
-    if (serializador != null) +  if (serializador != null) 
-        try { +    try { 
-            serializador.close(); +      serializador.close(); 
-        } catch (IOException ioe) { +    } catch (IOException ioe) { 
-            ioe.printStackTrace(); +      ioe.printStackTrace();
-        }+
     }     }
 +  }
 . . . . . .
 </code> </code>
  
-=== Deserializar objetos === +=== Deserializar un objeto ===
- +
-En el momento en que quiera recuperar esos datos almcenados en ''productos.dat'', sólo tengo que realizar la operación contraria y podré recuperar la colección original y seguir trabajando con ella.+
  
 <code java> <code java>
Line 115: Line 311:
 ObjectInputStream deserializador = null; ObjectInputStream deserializador = null;
 try { try {
-    deserializador = new ObjectInputStream(new FileInputStream("productos.dat")); +  deserializador = new ObjectInputStream(new FileInputStream("archivo.dat")); 
-    listaProductos = (ArrayList<Producto>)deserializador.readObject();+  listaProductos = (ArrayList<Producto>)deserializador.readObject();
 } catch (FileNotFoundException fnfe ) { } catch (FileNotFoundException fnfe ) {
-    fnfe.printStackTrace();+  fnfe.printStackTrace();
 } catch (ClassNotFoundException cnfe ) {  } catch (ClassNotFoundException cnfe ) { 
-    cnfe.printStackTrace();+  cnfe.printStackTrace();
 } catch (IOException ioe) {  } catch (IOException ioe) { 
-    ioe.printStackTrace();+  ioe.printStackTrace();
 } finally { } finally {
-    if (deserializador != null) +  if (deserializador != null) 
-        try { +  try { 
-            deserializador.close(); +    deserializador.close(); 
-        } catch (IOException ioe) {  +  } catch (IOException ioe) {  
-            ioe.printStackTrace(); +    ioe.printStackTrace(); 
-        }+  }
 } }
 . . . . . .
 </code> </code>
 +
 +===== Paquete Java NIO 2 =====
 +
 +No includo desde siempre, el paquete Java NIO 2, mejora las clases y métodos disponibles para trabajar con ficheros, sistemas de ficheros y todo lo relacionado con entrada/salida.
 +
 +==== FileSystems ====
 +
 +Es una factoría que permite acceder a un sistema de ficheros:
 +  * //static FileSystem getDefault()//: Devuelve el sistema de ficheros por defecto
 +
 +==== FileSystem ====
 +
 +Representa un sistema de ficheros
 +
 +  * //Path getPath(String first, String. . . more)//: Convierte una ruta en un objeto Path
 +  * //String getSeparator()//: Devuelve el separador de diretorio del sistema de ficheros
 +  * //FileSystemProvider getProvider()//: Devuelve el proveedor del sistema de ficheros
 +
 +==== Paths ====
 +
 +Contiene métodos estáticos para obtener objetos Path a partir de cadenas 
 +  * //static Path get(String first, String... more)//
 +
 +==== Path ====
 +
 +Representa un fichero dentro del sistema de ficheros.
 +Podemos acceder al fichero y a su información a través de las propiedades y métodos de la clase
 +  * //boolean endsWith(String string)//
 +  * //boolean endsWith(Path path)//
 +  * //int getNameCount()//
 +  * //Path getParent()//
 +  * //boolean startsWith(String string)//
 +  * //File toFile()//
 +  * //String toString()//
 +
 +==== Files ====
 +
 +Contiene métodos estáticos que operan con ficheros y directorios
 +  * //static long copy(. . .)//
 +  * //static Path createFile(. . .)//
 +  * //static void delete(. . .)//
 +  * //static boolean deleteIfExists(Path path)//
 +  * //static Stream<String> lines(Path path)//
 +  * //static Stream<Path> list(Path dir)//
 +  * //static List<String> readAllLines(Path path)//
 +  * //static List<String> readAllLines(Path path, Charset cs)//
 +  * //static String readString(Path path)//
 +  * //static long size(Path path)//
 +  * //static Stream<Path> walk(Path start, int maxDepth, FileVisitOption... options)//
 +  * //static Stream<Path> walk(Path start, FileVisitOption. . . options)//
  
 ---- ----
  
-(c) 2019 Santiago Faci+(c) 2019-{{date>%Y}} Santiago Faci
apuntes/ficheros.1550346565.txt.gz · Last modified: 2019/02/16 19:49 by Santiago Faci