6.2 Clasificación de archivos de texto y binarios
Los archivos de texto plano son aquellos que están compuestos únicamente por texto sin formato, solo caracteres. estos caracteres se pueden codificar de distintos modos dependiendo de la lengua usada. Se les conoce también como archivos de texto llano o texto simple por carecer de información destinada a generar formatos y tipos de letra.
Un archivo binario es una archivo informático que contiene información de cualquier tipo, codificada en forma binaria para el propósito de almacenamiento y procesamiento de ordenadores.
Muchos formatos binarios contienen partes que pueden ser interpretados como texto. Un archivo binario que solo contiene información de tipo textual sin información sobre el formato del mismo, se dice que es un archivo de texto plano. Habitualmente se contraponen los términos archivo binario y archivo de texto de forma que los primeros no contienen solamente texto.
6.3 Operaciones básicas y tipos de acceso
Introducción
Normalmente, cuando se codifica un programa, se hace con la intención de que ese programa pueda interactuar con los usuarios del mismo, es decir, que el usuario pueda pedirle que realice cosas y pueda suministrarle datos con los que se quiere que haga algo. Una vez introducidos los datos y las órdenes, se espera que el programa manipule de alguna forma esos datos para proporcionarnos una respuesta a lo solicitado.
Además, en muchas ocasiones interesa que el programa guarde los datos que se le han introducido, de forma que si el programa termina los datos no se pierdan y puedan ser recuperados en una sesión posterior. La forma más normal de hacer esto es mediante la utilización de ficheros que se guardarán en un dispositivo de memoria no volátil (normalmente un disco).
A todas estas operaciones, que constituyen un flujo de información del programa con el exterior, se les conoce como Entrada/Salida (E/S).
Existen dos tipos de E/S; la E/S estándar que se realiza con el terminal del usuario y la E/S a través de fichero, en la que se trabaja con ficheros de disco.
Todas las operaciones de E/S en Java vienen proporcionadas por el paquete estándar de la API de Java denominado java.io que incorpora interfaces, clases y excepciones para acceder a todo tipo de ficheros. En este tutorial sólo se van a dar algunas pinceladas de la potencia de este paquete.
Entrada/Salida estándar
Aquí sólo trataremos la entrada/salida que se comunica con el usuario a través de la pantalla o de la ventana del terminal.
Si creamos una applet no se utilizarán normalmente estas funciones, ya que su resultado se mostrará en la ventana del terminal y no en la ventana de la applet. La ventana de la applet es una ventana gráfica y para poder realizar una entrada o salida a través de ella será necesario utilizar el AWT.
El acceso a la entrada y salida estándar es controlado por tres objetos que se crean automáticamente al iniciar la aplicación: System.in, System.out y System.err
a.) System.in
Este objeto implementa la entrada estándar (normalmente el teclado). Los métodos que nos proporciona para controlar la entrada son:
- read(): Devuelve el carácter que se ha introducido por el teclado leyéndolo del buffer de entrada y lo elimina del buffer para que en la siguiente lectura sea leído el siguiente carácter. Si no se ha introducido ningún carácter por el teclado devuelve el valor -1.
- skip(n): Ignora los n caracteres siguientes de la entrada.
b.) System.out
Este objeto implementa la salida estándar. Los métodos que nos proporciona para controlar la salida son:
- print(a): Imprime a en la salida, donde a puede ser cualquier tipo básico Java ya que Java hace su conversión automática a cadena.
- println(a): Es idéntico a print(a) salvo que con println() se imprime un salto de línea al final de la impresión de a.
c.) System.err
Este objeto implementa la salida en caso de error. Normalmente esta salida es la pantalla o la ventana del terminal como con System.out, pero puede ser interesante redirigirlo, por ejemplo hacia un fichero, para diferenciar claramente ambos tipos de salidas.
Las funciones que ofrece este objeto son idénticas a las proporcionadas por System.out.
Ejemplo
A continuación vemos un ejemplo del uso de estas funciones que acepta texto hasta que se pulsa el retorno de carro e informa del número de caracteres introducidos.
import java.io.*;
class CuentaCaracteres {
public static void main(String args[]) throws IOException {
int contador=0;
while(System.in.read()!='n')
contador++;
System.out.println(); // Retorno de carro "gratuito"
System.out.println("Tecleados "+contador+" caracteres.");
}
6.4 Manejo de objetos persistentes
Las clases presistentes son clases en una aplicación que implementan las entidades del problema empresarial (por ejemplo, Customer y Order en una aplicación de comercio electrónico). No se considera que todas las instancias de una clase persistente estén en estado persistente. Por ejemplo, una instancia puede ser transitoria o separada.
Hibernate funciona mejor si estas clases siguen algunas reglas simples, también conocidas como el modelo de programación POJO (Plain Old Java Object). Sin embargo, ninguna de estas reglas son requerimientos rígidos. De hecho, Hibernate3 asume muy poco acerca de la naturaleza de sus objetos persistentes. Puede expresar un modelo de dominio en otras formas (por ejemplo, utilizando árboles de instancias de Map).
Ejemplo simple de POJO
La mayoría de aplicaciones Java requieren una clase persistente que represente a los felinos. Por ejemplo:
package eg;
import java.util.Set;
import java.util.Date;
public class Cat {
private Long id; // identifier
private Date birthdate;
private Color color;
private char sex;
private float weight;
private int litterId;
private Cat mother;
private Set kittens = new HashSet();
private void setId(Long id) {
this.id=id;
}
public Long getId() {
return id;
}
void setBirthdate(Date date) {
birthdate = date;
}
public Date getBirthdate() {
return birthdate;
}
void setWeight(float weight) {
this.weight = weight;
}
public float getWeight() {
return weight;
}
public Color getColor() {
return color;
}
void setColor(Color color) {
this.color = color;
}
void setSex(char sex) {
this.sex=sex;
}
public char getSex() {
return sex;
}
void setLitterId(int id) {
this.litterId = id;
}
public int getLitterId() {
return litterId;
}
void setMother(Cat mother) {
this.mother = mother;
}
public Cat getMother() {
return mother;
}
void setKittens(Set kittens) {
this.kittens = kittens;
}
public Set getKittens() {
return kittens;
}
public void addKitten(Cat kitten) {
kitten.setMother(this);
kitten.setLitterId( kittens.size() );
kittens.add(kitten);
}
}
En las siguientes secciones vamos a explorar en mayor detalle las cuatro reglas principales de las clases persistentes.
Implemente un constructor sin argumentos
Cat tiene un contructor sin argumentos. Todas las clases persistentes deben tener un constructor predeterminado (el cual puede ser no-público) de modo que Hibernate pueda instanciarlas usando Constructor.newInstance(). Le recomendamos contar con un constructor por defecto con al menos una visibilidad de paquete para la generación de proxies en tiempo de ejecución en Hibernate.
Proporcione una propiedad identificadora (opcional)
Cat tiene una propiedad llamada id. Esta propiedad mapea a la columna de la llave principal de la tabla de la base de datos. La propiedad podría llamarse de cualquier manera y su tipo podría haber sido cualquier tipo primitivo, cualquier tipo de "wrapper" primitivo, java.lang.String o java.util.Date. Si su tabla de base de datos heredada tiene claves compuestas, puede utilizar una clase definida por el usuario con propiedades de estos tipos
La propiedad identificadora es estrictamente opcional. Puede olvidarla y dejar que Hibernate siga internamente la pista de los identificadores del objeto. Sin embargo, no recomendamos que esto suceda.
De hecho, algunas funcionalidades se encuentran disponibles sólamente para clases que declaran una propiedad identificadora:
- Session.saveOrUpdate()
- Session.merge()