Laboratorio de Programación Entrada / Salida (ficheros) Ejercicio e3 Dpto. de Ingeniería de Sistemas Telemáticos http://www.lab.dit.upm.es/~lprg/ Ficheros Donde se almacenan datos permanentemente disco duro: C:, $HOME discos removibles: MP-3, discos USB, ... Los datos son montones de bits se pueden interpretar como bytes de 8 en 8 bits byte b se pueden interpretar como caracteres de 16 en 16 bits char c 21.3.2007 entrada / salida + e3 2 1 Ficheros java.util.File File fichero= new File(“nombre”); File fichero= new File(“directorio”, “fichero”); métodos útiles boolean exists() String getName() String getPath() http://java.sun.com/j2se/1.5.0/docs/api/java/io/File.html 21.3.2007 entrada / salida + e3 3 Uso de ficheros Lectura 1. 2. 3. Escritura open read read ... close se abre para leer se leen porciones se cierra 1. 2. 3. open write write ... close se abre para escribir se escriben porciones se cierra NOTA: si no se cierra, pueden quedar partes sin guardar 21.3.2007 entrada / salida + e3 4 2 Lectura de bytes private static final int PORCION= 1024; String ficheroEntrada= ... InputStream entrada = new FileInputStream(ficheroEntrada); byte[] datos = new byte[PORCION]; int nDatos = entrada.read(datos); while (nDatos > 0) { // datos [ 0 a nDatos-1 ] nDatos = entrada.read(datos); } entrada.close(); NOTA: aunque se pide leer una PORCION de datos, puede que se lean menos 21.3.2007 entrada / salida + e3 5 Escritura de bytes String ficheroSalida= ... OutputStream salida = new FileOutputStream(ficheroSalida); while ( ... ) { byte[] datos = ... salida.write(datos); } salida.close(); NOTA: si no se cierra, pueden quedar partes sin guardar 21.3.2007 entrada / salida + e3 6 3 Lectura de caracteres private static final int PORCION= 1024; String ficheroEntrada= ... Reader entrada = new FileReader(ficheroEntrada); char[] datos = new char[PORCION]; int nDatos = entrada.read(datos); while (nDatos > 0) { // datos [ 0 a nDatos-1 ] nDatos = entrada.read(datos); } entrada.close(); NOTA: aunque se pide leer una PORCION de datos, puede que se lean menos 21.3.2007 entrada / salida + e3 7 Escritura de caracteres String ficheroSalida= ... Writer salida = new FileWriter(ficheroSalida); while ( ... ) { char[] datos = ... salida.write(datos); } salida.close(); NOTA: si no se cierra, pueden quedar partes sin guardar 21.3.2007 entrada / salida + e3 8 4 Ejercicio e3 Se trata de implementar un cifrador/descifrador que trabaje con ficheros, siguiendo los algoritmos de Vigenère Hay que tener en cuenta: Los ficheros pueden ser muy grandes, por lo que no es recomendable implementaciones de Vigenère “de un paso” (que podrían dejar la máquina sin memoria) Los ficheros binarios tienen bytes que no pertenecen al alfabeto usado por Vigenère (ej. ficheros .jpg, .mp3) 21.3.2007 entrada / salida + e3 9 Ejercicio e3 Material proporcionado C: \ java \ lprg \ e3 \ cifrador \ Vigenere.java C: \ java \ lprg \ e3 \ cifrador \ CifradorIncremental.java C: \ java \ lprg \ e3 \ cifrador \ DescifradorIncremental.java C: \ java \ lprg \ e3 \ base64 \ Codificador.java C: \ java \ lprg \ e3 \ base64 \ Descodificador.java C: \ java \ lprg \ e3 \ log \ Logger.java El alumno C: \ java \ lprg \ e3 \ cifrador \ ui \ CifradorFicheros.java 21.3.2007 entrada / salida + e3 10 5 Ejercicio e3 /** * Utilización desde consola. consola. * Para cifrar fichero: fichero: * java cifrador.ui.CifradorFicheros -c clave fichero fichero.vgn * Para descifrar fichero.vgn: fichero.vgn: * java cifrador.ui.CifradorFicheros -d clave fichero.vgn fichero * * @param @param args para indicar cifrar/descifrar, cifrar/descifrar, clave, ficheros de entrada y salida * @throws java.io.IOException si se producen errores en el tratamiento de ficheros. ficheros. */ 21.3.2007 entrada / salida + e3 11 Ejercicio e3 Hay que entregar $HOME \ lprg \ e3 \ cifrador \ ui \ CifradorFicheros.java Antes del viernes, 30 de marzo, a las 24:00 El codigo tiene que venir perfectamente documentado (javadoc) trazas 21.3.2007 entrada / salida + e3 12 6 Cifrador incremental Para cifrar/descifrar textos de gran tamaño (por ej. ficheros) es recomendable utilizar una implementación incremental de Vigenère: Secuencia de uso para cifrar/descrifrar: 1. lee un bloque de N caracteres 2. cifra/descifra con Vigenére 3. repite con otro bloque hasta terminar 21.3.2007 entrada / salida + e3 13 Cifrador incremental Variante del cifrador de Vigenere Trabaja sobre String sucesivas, sin volver a la clave inicial public class CifradorIncremental { public CifradorIncremental(String clave) { ... } public String cifra(String texto) { ... } } 21.3.2007 entrada / salida + e3 14 7 Descifrador incremental Variante del descifrador de Vigenere Trabaja sobre String sucesivas, sin volver a la clave inicial public class DescifradorIncremental { public DescifradorIncremental(String clave) { ... } public String descifra(String texto) { ... } } 21.3.2007 entrada / salida + e3 15 CifradorIncremental 21.3.2007 entrada / salida + e3 16 8 Cifrado de bytes Vigenère sólo cifra mensajes dentro del alfabeto Base64 codifica cualquier secuencia de bytes convirtiéndola en un texto dentro del alfabeto: private static final String ALFABETO = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstu vwxyz0123456789+/"; Para cifrar cualquier dato (secuencia de bytes): bytes base64 texto Vigenére criptograma clave 21.3.2007 entrada / salida + e3 17 Base64 Una forma de meter bits en caracteres “normales” Un byte son 8 bits 3 bytes son 24 bits 24 bits son 4 códigos de 6 bits con 6 bits se tienen 26 combinaciones (64) cada código se asigna a un carácter de "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn opqrstuvwxyz0123456789+/“ Si faltan bytes, se rellena con “=“ 21.3.2007 entrada / salida + e3 18 9 base64 Secuencia de uso: 1. new Codificador() 2. se llama N veces a codifica(byte[]) 3. se llama a termina() 21.3.2007 Secuencia de uso: 1. new Descodificador() 2. se llama N veces a descodifica (String) entrada / salida + e3 19 Codificador base64 Se le pasan bytes devuelve Strings codificadas public class Codificador { public Codificador() { ... } public String codifica(byte[] data) { ... } public String codifica(byte[] data, int from, int length) { ... } public String termina() { ... } } 21.3.2007 entrada / salida + e3 20 10 Descodificador base64 Se le pasan Strings devuelve bytes public class Descodificador { public Descodificador() { ... } public byte[] descodifica(String data) { ... } public byte[] descodifica(String data, int from, int length) { ... } } 21.3.2007 entrada / salida + e3 21 Cifrador de ficheros Para cifrar cualquier fichero: fichero texto InputStream byte[] CifradorIncremental base64.Codificador criptograma Writer texto fichero.vgn clave Para descifrar un fichero.vgn: fichero texto OutputStream byte[] DescifradorIncremental base64.Descodificador criptograma Reader texto fichero.vgn clave 21.3.2007 entrada / salida + e3 22 11 E3: cifrar ficheros 1. 2. 3. 4. 5. Se prepara un codificador Base64 Se prepara un cifrador incremental Se abre un fichero de bytes de lectura Se abre un fichero de caracteres de escritura mientras hay bytes 1. 2. 3. 4. 6. se lee una PORCION de bytes se codifican en base64 se cifran se escriben Se cierran los ficheros 21.3.2007 entrada / salida + e3 23 E3: descifrar ficheros 1. 2. 3. 4. 5. Se prepara un descodificador Base64 Se prepara un descifrador incremental Se abre un fichero de caracteres de lectura Se abre un fichero de bytes de escritura mientras hay caracteres 1. 2. 3. 4. 6. se lee una PORCION de caracteres se descifran se descodifican en base64 se escriben Se cierran los ficheros 21.3.2007 entrada / salida + e3 24 12 E3: trazas Debe el alumno Crear un Logger de nombre "cifrador.ui.CifradorFicheros" Generar un traza a nivel INFO que indique: si se está cifrando o descifrando, la clave utilizada y los nombres de los ficheros de entrada y de salida Generar trazas a nivel FINE cada vez que se lea un bloque de datos del fichero de entrada, indicando el número total de datos (bytes o caracteres) leídos hasta el momento. 21.3.2007 entrada / salida + e3 25 13