Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Programación III
¿Qué es la memoria?
En realidad Pero es más fácil verlo como
00000000 byte
00000001 byte
byte
. byte
.
. .
.
.
dato
dato
obj
obj
FFFFFFFF
Programación III
Arrays / contiguidad
¿Dónde array[0]? ¿Y array[n]? ¿Qué necesitamos?
00000000
00000001
.
.
.
Serie de elementos
02a37f14
array
array
FFFFFFFF
Programación III
¿Modificación? Sec. NO
Random SÍ
¿Borrado? Sec. NO
Random no/marca
Tbytes
milisegundos
Gbytes Persistente
Nanosegundos Necesita I/O
Volátil
Accesible (Random Access)
Programación III
Ficheros secuenciales y random
Similitud entre memoria primaria y secundaria
0000000000
0000000001
.
.
.
Fichero secuencial
0002a37f14
fich
Fichero secuencial / aleatorio
FFFFFFFFFF
Programación III
¿Y una base de datos?
BD = varios ficheros con estructura y relaciones (tablas)
Índices = arrays sobre estructuras aleatorias
Las claves primarias se gestionan ordenadas con índices
Programación III
java.io: clase File
• Objeto inmutable, representa un fichero o carpeta
• Diferente entre SSOO ("\\", "/")
• Algunos métodos:
– getName(), getParent(), getAbsolutePath()
• toURI()
– exists(), isDirectory(), isFile()
– isHidden(), lastModified(), length()
– list( [filtro] ), listFiles( [filtro] )
– renameTo( f ), delete() [no hay copy!]
– mkdir(), mkdirs()
Programación III
File vs Resource
• File:
– Objeto para referencia a fichero (disco/red)
– Sistema físico de ficheros/comunicaciones
– Partiendo de la carpeta de inicio del proyecto
• Puede navegar en absoluto o relativo (..)
• Resource:
– Parte de la estructura de una clase
• Solo navega hacia adelante de ese punto
– Puede acceder a datos empaquetados que carga el
loader (por ej. en ficheros .jar) en memoria
– Usado fundamentalmente en solo lectura
Programación III
java.io: Streams
– Bytes: FileInputStream, FileOutputStream
– Buffer: BufferedInputStream, BufferedOutputStream
• Texto: BufferedReader,
BufferedWriter, PrintStream
• Objetos: ObjectInputStream, ObjectOutputStream
• Acceso directo: RandomAccessFile (seek)
– Binarios: FileInputStream / FileOutputStream ☺
– Puede ser útil ByteBuffer (convierte datos a arrays
de bytes)
Programación III
java.nio (Java 7)
• Se puede copiar y recorrer
– Clase java.nio.files.Files
• copy( fuente, destino, opciones )
• delete, exists, move, create...
• Recorrer: walk, walkFileTree
• Globs (patrones simplificados. Ej: *.html, Pr??.java)
• Monitorización de cambios en ficheros/carpetas
– (ver MonitorizaDisco.java)
• Path para mejorar File:
Programación III
Lógica de datos
• En cada proyecto nos tenemos que plantear
– ¿Qué datos son fijos y cuáles variables?
– ¿Qué datos deben perdurar entre ejecuciones?
– ¿Podemos cargar todos los datos en memoria?
• ¿Nos caben? ¿Es eficiente?
• Para cada tipo de datos necesitaremos definir una
estrategia de acceso a esos datos
– Veamos algunas
Programación III
Datos fijos en memoria
• Si los datos que necesitamos no cambian y son pocos,
podemos definirlos en el mismo programa
– Como un array u otra estructura (mapa,lista)
– Ejemplos:
String[] diasSem = {"lunes", "martes", ... "domingo"};
Usuarios administradores = {
new Usuario( "andoni", "miclave" ), ... };
Programación III
Datos variables y heterogéneos
• Si los datos cambian y son pocos, se pueden usar
ficheros de texto (.ini, .cfg, .prop, .xml...)
– Fichero de "configuración" de aplicación
– Método de carga inicial de fichero a memoria
– Método de cambio (de algún dato)
• Guardando de nuevo el fichero
– Ejemplos: carpeta en curso, último usuario con login,
fecha último acceso...
carpeta=c:\users\all\datos
usuario=maria
ventana=640,400
Programación III
Cómo guardar datos variables?
• A mano
– Con ficheros de texto
• Con la API de Java
– En fichero de texto - Properties
• setProperty( clave, valor )
• getProperty( clave )
• loadFromXML( fic ) / storeToXML( fic, título )
• (ver EjemploProperties.java)
– En registro de sistema - Preferences
• (ver ejemplo en cap. 1)
Programación III
Datos variables homogéneos
• Habitualmente nos encontraremos:
– Tenemos "n" objetos con los que trabajar
– Hay que guardarlos entre ejecuciones de la
aplicación para poder acceder a ellos
• Aspectos a considerar:
– ¿Caben todos en memoria?
• ¿Cuándo los guardamos?
– ¿Puede cambiar su estructura con el tiempo?
(nuevos atributos)
Programación III
Enfoque 2: Ficheros binarios
• Java permite serializar objetos
– Cargar al principio, guardar al final
– Un fichero por cada tipo de objeto (clase)
– writeObject(o), readObject()
• ¿Cómo funciona?
– Java escribe todos los atributos de cada objeto
– Se guarda en formato binario consecutivamente en
el fichero
– Cualquier cambio en la estructura del objeto hará
que no se puedan leer ficheros anteriores
• Se leen Object - hay que hacer un cast
Programación III
Ficheros binarios: Serializable
– Toda clase que queramos guardar debe implementar
el interfaz java.io.Serializable
• Sin métodos
• Debe asociar un número de versión único
static final long serialVersionUID = 1234567890L;
• Cada writeObject() guarda ese número y todos los datos
• Cada readObject() lee ese número y lo compara al
interpretar el objeto que se ha leído
(InvalidClassException)
– Todos los atributos y las superclases deben ser a su
vez serializables
• Deben tener constructor vacío - lo usa el readObject()
Programación III
Ejemplo de serialización
private void escribeAFichero() {
try {
FileOutputStream fout = new FileOutputStream(“a.dat");
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject( miDato );
oos.close();
} catch (IOException e) { ... }
}
private void leeDeFichero() {
try {
FileInputStream fin = new FileInputStream(“a.dat");
ObjectInputStream ois = new ObjectInputStream(fin);
miDato = (MiClase) ois.readObject();
ois.close();
} catch (Exception e) { ... }
} (ver EjemploFicheros.java)
Programación III
Enfoque 1: Ficheros de texto
– Un fichero por tipo de objeto (clase)
– Cada clase debe tener al menos:
• Un lector del fichero (cargaDeFic( ... ))
• Un escritor del fichero (guardaEnFic( ... ))
– El formato del fichero puede ser libre o estándar
(XML, el más utilizado)
– Es recomendable utilizar etiquetas
• Permiten que cambios de atributos en la clase sean
soportables, identificando qué dato se lee (versiones
acumulativas de los métodos lectores)
Programación III
Ficheros de texto (2)
• Por ejemplo un fichero de texto de usuarios podría
tener esta pinta si separamos sus atributos con comas:
Andoni,Eguíluz Morán,miPass,636124523
Luis,Gómez Ruiz,xxyyww84,666000111
...
Programación III
Ficheros de texto (3)
• Podríamos también separar por líneas sus atributos, o
incluso poner tags para evitar posibles errores:
[USUARIO]
[Nombre]Andoni
[Apellidos]Eguíluz Morán
[Contraseña]Aquí la voy a poner!
[FINUSUARIO]
[USUARIO]
[Nombre]Luis
[Apellidos]Gómez Ruiz
[Contraseña]xxyyww84
[FINUSUARIO]
Programación III
Ficheros de texto (4)
• O mejor usar un formato estándar XML:
<root>
<USUARIOS>
<USUARIO>
<nombre valor="Andoni"/>
<apellidos valor="Eguíluz Morán/>
<contraseña valor="Aquí la voy a poner!"/>
</USUARIO>
<USUARIO>
<nombre valor="Luis"/>
<apellidos valor="Gómez Ruiz/>
<contraseña valor="xxyyww84"/>
</USUARIO>
</USUARIOS>
</root>
Programación III
Programando la lectura
• Por ejemplo: (ver EjemploFicheros.java)
try {
BufferedReader brFich = new BufferedReader( new
InputStreamReader( new FileInputStream(nomFic) ) );
String linea = brFich.readLine();
while (linea != null) {
// Proceso de línea
// (depende de cómo esté implementado)
...
linea = brFich.readLine();
}
brFich.close();
} catch (Exception e) { // FileNotFound, IO
e.printStackTrace();
}
Programación III
Escritura de ficheros de texto
• Por ejemplo:
try {
BufferedWriter brFich = new BufferedWriter( new
OutputStreamWriter(new FileOutputStream(nomFic)) );
for (DatoAEscribir d : miEstructuraDeDatos) {
// Proceso de dato a línea
// Depende del modo de escritura
...
}
brFich.close();
} catch (Exception e) {
e.printStackTrace();
}
Programación III
Enfoque 3: Base de datos
– Si los datos no caben en memoria, o si queremos
guardar cada cambio y no toda la estructura, bases
de datos en lugar de ficheros
• Acceso a un solo dato sin leer todo el fichero
• Acceso a datos buscando por criterios configurables
– Estructura optimizada para la búsqueda
• Relaciones entre datos (tablas)
Programación III
Base de Datos
• Java no incluye ningún SGBD
– Pero sí una API para enlazar con cualquier BD: JDBC
– Por ejemplo, SQLite
• Driver JDBC-SQLite: https://bitbucket.org/xerial/sqlite-jdbc
(Hay que enlazar el .jar en el classpath)
• (Opcional) Sistema visual de administración de la BD:
http://sourceforge.net/projects/sqliteman/
(Otra opción, válida para Mac: http://sqlitebrowser.org/)
• Web general: http://www.sqlite.org/
• SQLite no tiene un SGBD adicional, ni necesita servidor, es
un programa (que va incluido en el .jar)
Programación III
ResulSet ResulSet ResulSet
• Estructura Statement
Prepared Callable
Statement Statement
JDBC
Connection
Application
DriverManager
JDBC-ODBC
Oracle Driver Sybase Driver
Bridge
ODBC Driver
Oracle Sybase
Database Database
ODBC
Database
Programación III
Driver JDBC
– Todas la configuraciones necesitan de un driver JDBC
específico para la base de datos que se vaya a usar.
– Para ejemplos usaremos el driver JDBC-SQLite
• Integra con un .jar que incluye el motor SQLite.
• Otras opciones: JDBC - ODBC
• Lo normal es una pasarela que conecta con la BD instalada
en el SO (Oracle p ej.)
Programación III
Inicio de código BD
• Importar clases de JDBC:
import java.sql.*;
• Cargar driver (class loader)
Class.forName("org.sqlite.JDBC");
• Establecer conexión / lanzar sents. SQL:
Connection conn = null;
try {
conn = DriverManager.getConnection(
“jdbc:sqlite:n.db“ );
Programación III
Sentencia JDBC
• Crear un objeto JDBC Statement
– Los objetos Statement son necesarios para ejecutar
sentencias SQL sobre la base de datos.
– Los objetos Statement se crean a través del objeto
Connection.
Statement stmt = conn.createStatement();
– Dos tipos de sentencias SQL:
• Consultas SQL ➔ Método executeQuery()
• Sentencias que modifican la BD ➔ Método
executeUpdate()
Programación III
executeUpdate()
– Para sentencias de tipo INSERT, DELETE, UPDATE, CREATE,
DROP, ALTER,...
– Ejemplos:
• Inserción de una nueva fila en la tabla alumnos
String sentencia = "INSERT INTO ALUMNOS
VALUES('666','JORGE RUIZ',26)";
stmt.executeUpdate(sentencia);
• Borrado de una fila de la tabla alumnos
String sentencia = "DELETE FROM ALUMNOS WHERE
EDAD = 20";
stmt.executeUpdate(sentencia);
• Modificación del contenido de una fila de la tabla alumnos
String sentencia = "UPDATE ALUMNOS SET EDAD=19
WHERE DNI = '666'";
stmt.executeUpdate(sentencia);
Programación III
executeQuery()
• Método EXECUTEQUERY
– Para sentencias SQL de tipo “SELECT” (consultas)
– Ejemplos:
• Obtener todos los alumnos de la tabla alumnos
stmt.executeQuery(“SELECT * FROM ALUMNOS”);
• Obtener el dni y el nombre de los de 22 años
String query = “select dni, nombre from
Alumnos where edad = 22”;
stmt.executeQuery(query);
– Estas consultas SQL devuelven como resultado un conjunto
de filas ➔ ¿Cómo podemos recoger estos resultados?
Programación III
ResultSet
• Manipulación de los resultados generados
– El interfaz ResultSet nos permite recoger los
resultados (filas) generados por una consulta SQL.
Objeto “tabla” con filas y columnas.
– Posee una serie de métodos para “navegar” entre las
filas y columnas de dicha tabla resultado: next( ) y
getXXX( )
– Método getXXX( nombreCampo / posCampo )
• Recupera valor de una columna de la fila en curso.
• getInt( ) -> INTEGER / getFloat( ) -> REAL
• getDouble( ) -> FLOAT, DOUBLE
• getString( ) ->CHAR, VARCHAR, LONGVARCHAR
• getBoolean( ) -> BIT
Programación III
ResultSet (2)
– Ejemplo:
• Consulta a realizar: “SELECT NOMBRE, EDAD FROM ALUMNOS”
• Tabla resultado que se obtiene:
NOMBRE EDAD
Jane Markham 23
Louis Smith 21
Woodrow Lang 32
John Smith 19
Programación III
Ejemplo ResultSet
Statement stmt = con.createStatement();
String query = “SELECT NOMBRE, EDAD FROM ALUMNOS”;
ResultSet rs = stmt.executeQuery(query);
while(rs.next())
{
System.out.print(“Nombre: ” + rs.getString(1));
System.out.print(“, ”);
System.out.println(“Edad: ” + rs.getInt(“EDAD”));
}
rs.close();
Programación III
Acabando...
• Cerrar los recursos abiertos
• Las Connection
• Los Statement
• Los Resultset
– ... mediante el método close( )
rs.close();
stmt.close();
con.close();
Programación III
Excepciones JDBC
• La mayoría de las operaciones del API JDBC pueden lanzar la
excepción SQLException.
• Esta excepción se produce cuando se da algún error en el
acceso a la base de datos (error de conexión, sentencias
SQL incorrectas,...)
• Por tanto, será necesario capturarla:
try{
...
}
catch(SQLException se){
System.out.println(“SQL Exception: “ +
se.getMessage());
se.printStackTrace(System.out);
}
Programación III
¿Y el SQL?
• La sintaxis la procesa el SGBD, Java sólo pasa el string
con la sentencia completa
– Sintaxis SQL
• INSERT INTO tabla (campo1, campo2) VALUES
(valor1, valor2)
• UPDATE tabla SET campo1 = valor1, campo2 =
valor2 [WHERE campo1 = valor1]
• DELETE FROM tabla WHERE campo = valor
– Comillas simples para Strings / doble ' para '
– Evitar caracteres especiales
– Y mucho cuidado al construir sentencias largas...
Programación III
Minipráctica
• Clase con main():
– 1. Crear tabla Usuario con campos nick, pass
– 2. Añadir una fila 'admin' - 'admin' [insert]
– 3. Comprobar creación/datos con SQLiteMan
– 3. Probar a ejecutar otra vez ¿cómo arreglarlo?
– 4. ¿Cómo hacer que solo se inserte 'admin' si no
existe ya antes? [select]
– 5. Hacer una pequeña ventana que permita insertar
usuarios nuevos de forma interactiva
– 6. Añadir a la ventana botón de borrado
– 7. ¿Puedes hacer que esto casque? ¿Cómo?
Programación III
¿Es esta la mejor manera?
• Crear strings con sentencias SQL es fácil pero...
– Errores de lógica (concatenaciones)
– Peligros de datos (SQL injections):
https://www.hacksplaining.com/exercises/sql-
injection
• Los strings deben ser "saneados" antes de ser introducidos
en las sentencias
– No es la forma más eficiente
• Está bien usarlo para empezar, pero no es la mejor
manera de programar el día de mañana:
– Sentencias preparadas (Java)
– Procedimientos almacenados (SGBD)
Programación III
PreparedStatement
• Ayudan a crear sentencias rellenando valores
Programación III
Transacciones
• En programación de BD sencilla no hacen falta
– Cada execute hace y confirma la sentencia
• Pero si queremos permitir recuperación de un proceso
complejo que funciona en bloque...
try {
con.setAutoCommit(false);
... varias actualizaciones de BD ...
con.commit();
} catch (SQLException e ) {
try {
con.rollback();
} catch(SQLException excep) {}
} finally {
con.setAutoCommit(true);
}
Programación III
Cómo gestiono los datos
• Si son pocos:
– 1. Cargar de fichero (BD) a memoria
– 2. Manejar en memoria
– 3. Reescribir en fichero (BD)
• Si son muchos o en cualquier caso en BD:
– 1. Abrir BD
– 2. Buscar-modificar en BD
– 3. Cerrar BD
Programación III
Particularidades
• boolean es un tipo que varios SGBD no soportan
• bigint (el long de Java) también depende
• date – revisar formato en cada SGBD (usualmente
AAAA/MM/DD)
• binarios – permitido pero distinto en cada SGBD.
Cuando queremos guardar un recurso multimedia, es
muy habitual guardar el path y gestionar aparte el
fichero (fuera de la BD)
Programación III
Razonamiento sobre BD/Clases
• Ejemplos de datos de vuestros proyectos
– ¿Qué tablas?
– ¿Qué clases/objetos?
• Relaciones
– Tabla simple (1 a 1)
– 1an
– nan
– Herencia
Programación III
Clase a tabla (1 a 1)
Carta
int numero
Palo palo
int valor
Clase
Tabla Carta
id: integer
numero: integer
palo: char(10)/integer
valor: integer
Tabla
Programación III
Clase a tabla (1 a n)
Tabla Pista
Pista
idPista: integer
String nombre nombre: varchar(100)
Deporte codDeporte codDeporte: char(15)
String localización loc: varchar(100)
ArrayList<Reserva>
reservas
Tabla Reserva
idReserva: integer
Reserva codUsuario: char(10)
horaInicio: integer
String codUsuario horaFin: integer
int horaInicio numDeportistas: int
int horaFin conLuz: bit
int numDeportistas
boolean conLuz numSec: integer
idPista: integer
Clases Tablas
Programación III
1 a n – también con repets
Pedido
String cliente
Date fecha
double importe Tabla Pedido
ArrayList<String> idPedido: integer
lineas cliente: varchar(100)
fecha: date
importe: float
Tabla LineaPedido
linea: varchar(1000)
numSec: integer
idPedido: integer
Clases Tablas
Programación III
Clase a tabla (m a n)
MapaNivel Tabla MapaNivel
Tabla Tile
Tile
posX: integer
TileModel tileModel posY: integer
int posX idMapaNivel: integer
int posY idTileModel: integer
driver (jar)
Programación III
¿Cómo ir a la nube?
– Servidor propio o servicio contratado/gratuito
• Por ejemplo www.heroku.com
– Instalar un servidor de base de datos
• Por ejemplo postgres (www.postgresql.org/)
– Acceder con SQL y el driver que corresponda
https://jdbc.postgresql.org/download.html
Class.forName("org.postgresql.Driver");
– Cadena de conexión que corresponda
"jdbc:postgresql://urlbd?sslmode=require"
urlbd = nombreservidor:5432/nombrebd
– Administración adicional si se requiere
• Por ejemplo EMS SQL Manager for PostgreSQL
Programación III
¿Seguridad en la nube?
– Arquitectura más fácil: BD pública (usu/pass)
driver
driver
–
• Comunicación supervisada, acceso BD centralizado
Programación III
Ejemplo de arquitectura C/S
• Ver paquete es.deusto.prog3.cap03.cs
• Programa Servidor (ejecutar 1)
• Programa Cliente (ejecutar n)
• Solo el servidor accede a la BD
Programación III
Ejercicios
• Toma cualquier clase sencilla que tengas definida y
realiza métodos para guardar y cargar los objetos de
esta clase a ficheros de texto, binarios, y bases de
datos.
• Prueba a visualizar y modificar la estructura de la BD
con sqliteman.
• Crea una base de datos remota en heroku y prueba a
acceder a ella con postgresql.
Programación III
Ejercicios 2
• En el paquete ejemploPartidas…
– Falta algo importante. Busca errores probando a hackear
la BD con testcase nuevo que meta algún apellido
irlandés (¿O’Reilly?). Solucionar BD.java
– Añadir el update de tabla de puntuación y añadir test de
ese update (¿qué hay que añadir?)
– Modificar alguno de los métodos con
preparedStatements en lugar de statements normales
– Programa un ejemplo que meta varios usuarios /
puntuaciones en la BD y observa esas tablas con el
administrador de sqlite
– Si te va bien para el proyecto… programa una edición de
ventana interactiva de usuario/partidas con este modelo
de BD o algún cambio
Programación III
Anexo: resumen SQL
• Operativa datos (CRUD):
– SELECT col1, col2,... colN FROM tabla
[WHERE condición]
[ORDER BY col {ASC|DESC}]
– SELECT * FROM tabla ...
– INSERT INTO tabla (col1, col2,... colN)
VALUES (val1, val2... valN)
– UPDATE tabla SET col1 = val1, col2 = val2...
[WHERE condición]
– DELETE FROM tabla WHERE condición
Programación III
Resumen SQL (2)
• Modificación estructura de BD:
– CREATE TABLE table_name(
col1 datatype,
col2 datatype, ...
PRIMARY KEY(col1, col2,...)
)
– DROP TABLE tabla;
– ALTER TABLE tabla {ADD|DROP|MODIFY} col
{datatype}
– CREATE DATABASE basedatos;
https://www.tutorialspoint.com/sql/sql-syntax.htm
Programación III
Anexo 2: Proceso XML
• Como es tan habitual trabajar con ficheros XML, Java
incorpora varias maneras de trabajar con ellos en su
API
– Preferences genera y lee XML
– Logger genera XML
– ...
• Si queremos procesarlo (p.ej. para los logs) hay una
minilibrería llamada SAX que lo permite muy fácilmente
– Ver EjemploProcesoLog.java
Programación III