Persistència en fitxers

Path operations

Paths , Path , Files

Un objecte de classe Path conté el nom de fitxer i la llista de directoris que s’utilitzen per construir el camí i s’utilitza per examinar, localitzar i manipular fitxers i directoris.

Per a obtenir un objecte Path utilitza el mètode static Paths.get()

Path path = Paths.get("/ruta/al/fitxer/o/directori");

Exemples

// obtenir el nom d'un fitxer, i unir-lo a la ruta d'un altre directori Path file = Paths.get("/usr/local/file.txt"); Path dir = Paths.get("/home/user"); System.out.println(dir.resolve(file.getFileName())); // /home/user/file.txt // relativitzar una ruta respecte a una altra Path file = Paths.get("/a/b/c/d.txt"); Path dir = Paths.get("/a/b/"); System.out.println(dir.relativize(file)); // c/d.txt

La classe Files conté mètodes estàtics per a fer operacions sobre fitxers i directoris

// crear un directori i els seus parents Files.createDirectories(Paths.get("/some/non/existing/directories")); // Imprimir el contingut d'un directori Files.list(Paths.get("/some/directory")).forEach(System.out::println); // Obtenir la llista dels continguts niats d'un directori List<Path> list = Files.walk(Paths.get("/this/directory")).collect(Collectors.toList()); // Imprimir els fitxers regulars d'un directori ordenats per tamany Files.list(Paths.get("/another/directori")) .filter(Files::isRegularFile) .sorted(Comparator.comparingLong(path -> { try { return Files.size(path); } catch (IOException e) { return 0; }})) .forEach(System.out::println); // Obtenir l'any, mes i dia de la data d'ultima modificació Path file = Paths.get("/one/more/file"); LocalDateTime time = LocalDateTime.parse(Files.getLastModifiedTime(file).toString(), DateTimeFormatter.ISO_DATE_TIME); System.out.println(time.getYear()); System.out.println(time.getMonthValue()); System.out.println(time.getDayOfMonth());

Exercici 1 - Flatten

Fes un programa que rebi com a argument la ruta d'un directori i "aplani" (flatten) el seu contingut, és a dir, que mogui a aquest mateix directori tots els fitxers que tingui niats. També haurà d'esborrar tots els directoris niats. Per exemple, si executem el programa amb aquest directori "niats":

hauria de quedar així:

Utilitza aquestes comandes per a crear l'arbre de prova

rm -r /tmp/flatten; mkdir -p /tmp/flatten/aaa/bbb/../ccc/ddd/../../eee/../../fff; touch /tmp/flatten/aaa/a.txt /tmp/flatten/aaa/a2.txt /tmp/flatten/aaa/bbb/b.txt /tmp/flatten/aaa/ccc/c.txt /tmp/flatten/aaa/ccc/ddd/d.txt /tmp/flatten/aaa/eee/e.txt /tmp/flatten/fff/f.txt /tmp/flatten/n.txt

Exercici 2 - Treediff

Fes un programa que rebi com a arguments dos directoris (DirectoriA i DirectoriB). El programa haura de comparar els fitxers niats (nested) dels dos directoris i dir:

  1. Els fitxers que estan al DirectoriA i no estan al DirectoriB
  2. Els fitxers que estan al DirectoriB i no estan al DirectoriA
  3. Els fitxers que estan al DirectoriA i al DirectoriB, però en diferents rutes
  4. Els fitxers que estan al DirectoriA i al DirectoriB, a la mateixa ruta

(quan diem que "està en una altra ruta" significa que o bé està en un altre directori (relatiu a DirectoriA o DirectoriB) o bé té un altre nom)

Per a saber si dos fitxers son iguals caldrà fixar-se en el seu contingut. S'haurà de fer un hash del contingut de cada fitxer i comparar-los. Ho pots fer així:

Path file1 = Paths.get("/aqui/esta/file1"); Path file2 = Paths.get("/alla/esta/file2"); byte[] hash1 = MessageDigest.getInstance("MD5").digest(Files.readAllBytes(file1)); byte[] hash2 = MessageDigest.getInstance("MD5").digest(Files.readAllBytes(file2)); if (Arrays.equals(hash1, hash2)) { // els fitxers file1 i files2 tenen el mateix contingut }

Arbre de prova:

rm -r /tmp/dirA; rm -r /tmp/dirB; mkdir -p /tmp/dirA/../dirB; echo "hola" > /tmp/dirA/hola.txt; echo "hola" > /tmp/dirB/hola.txt; echo "adeu" > /tmp/dirA/adeu.txt; echo "adeu" > /tmp/dirB/adeu2.txt; echo "jaja" > /tmp/dirA/jaja.txt; echo "jojo" > /tmp/dirB/jaja.txt; echo "jiji" > /tmp/dirB/jiji.txt; mkdir /tmp/dirA/subdirA; mkdir /tmp/dirB/subdirA; echo "damdamdam" > /tmp/dirA/subdirA/dam.txt; echo "damdamdam" > /tmp/dirB/subdirA/dam.txt; echo "madmadmad" > /tmp/dirA/subdirA/mad.txt; echo "madmadmad" > /tmp/dirB/subdirA/nomad.txt

Exercici 3 - DateTree

Fes un programa que rebi com a argument un directori i organitzi els seus fitxers niats en directoris segons l'any, mes i dia de la seva data de l'última modificació.

Per exemple, si cridem al programa amb aquest directori:

Hauria de quedar així:

Arbre de prova:

rm -r /tmp/directori; mkdir -p /tmp/directori/aaa/bbb/ccc/../../../ddd; touch -t 202001030000 /tmp/directori/aaa/a.txt; touch -t 202011190000 /tmp/directori/aaa/bbb/b.txt; touch -t 202001190000 /tmp/directori/aaa/bbb/ccc/c.txt; touch -t 202110270000 /tmp/directori/ddd/d.txt; touch -t 201911240000 /tmp/directori/e.txt

Orientat a bytes

OutputStream / InputStream

write()

// escriure bytes a un fitxer OutputStream os = Files.newOutputStream(path); os.write(63); os.write(127); os.write(33);

read()

// llegir un byte d'un fitxer InputStream is = Files.newInputStream(path); int a = is.read(); // llegir tots els bytes un a un InputStream is = Files.newInputStream(path); for (int a; (a = is.read()) != -1;){ System.out.println(a); }

Exercici 4 - Split/Join

Fes un programa que accepti com a argument la ruta d'un arxiu i nombre de parts. El programa dividirà (split) aquest arxiu en la quantitat de parts especificada. Els arxius amb les parts estaran a la mateixa ruta que l'arxiu original, però afegint al final l'extensió .part.$i (on $i és el número d'ordre de cada part).

Exemple:

Donats com a arguments la ruta /carpeta/foto.jpg que s'ha de dividir en 4 parts, el programa agafarà aquest arxiu:

/carpeta/foto.jpg 1024 bytes

i el dividirà en aquests 4 arxius:

/carpeta/foto.jpg.part.0 256 bytes /carpeta/foto.jpg.part.1 256 bytes /carpeta/foto.jpg.part.2 256 bytes /carpeta/foto.jpg.part.3 256 bytes

D'una altra banda el programa també permetrà fer la inversa, és a dir, ajuntar (join) les diverses parts d'un arxiu per a formar l'arxiu original. El programa acceptarà com a argument la ruta d'un arxiu i buscarà totes les parts amb aquesta ruta que tenen afegida l'extensió .part.$i ajuntant-les per a formar l'arxiu.

Exemple:

Donada com a argument la ruta /carpeta/foto.jpg, el programa agafarà les parts que hi hagi:

/carpeta/foto.jpg.part.0 256 bytes /carpeta/foto.jpg.part.1 256 bytes /carpeta/foto.jpg.part.2 256 bytes /carpeta/foto.jpg.part.3 256 bytes

i les ajuntarà en aquest arxiu:

/carpeta/foto.jpg 1024 bytes

Orientat a caracters

UTF-8

First code pointLast code pointByte 1Byte 2Byte 3Byte 4
00000007F1270xxxxxxx
008012807FF2047110xxxxx10xxxxxx
08002048FFFF65535110xxxxx10xxxxxx10xxxxxx
100006553610FFFF1114111110xxxxx10xxxxxx10xxxxxx10xxxxxx

BufferedWriter / BufferedReader

write("A"), escriu el codepoint del caracter "A" codificat amb UTF-8.
write(65), escriu el codepoint 65 codificat en UTF-8

// Escriure caracters try (BufferedWriter bw = Files.newBufferedWriter(Paths.get("string2.txt"))){ bw.write("A"); bw.write(8986); bw.write("Java"); bw.write(new char[]{'T','M'}); } catch (IOException e) { e.printStackTrace(); }

read()

// llegir caracters try (BufferedReader br = Files.newBufferedReader(Paths.get("file.txt"))){ char a = (char) br.read(); } catch (IOException e) { e.printStackTrace(); }

readLine()

// llegir una línia try (BufferedReader br = Files.newBufferedReader(Paths.get("file.txt"))){ String l = br.readLine(); } catch (IOException e) { e.printStackTrace(); }

Files.writeString / Files.write / Files.lines

Files.writeString()

// escriure un string try { Files.writeString(Paths.get("string.txt"), "This is a string"); } catch (IOException e) { e.printStackTrace(); }

Files.write()

// escriure cada String d'una List en una nova línia List<String> lines = Arrays.asList("linea1","linea2", "linea3"); try { Files.write(Paths.get("lines.txt"), lines); } catch (IOException e) { e.printStackTrace(); }

Files.lines()

// llegir varies linies en un Stream try (Stream<String> lines = Files.lines(Paths.get("lines.txt"))) { lines.forEach(System.out::println); } // --- alternativa try { Files.lines(Paths.get("lines.txt")) .forEach(System.out::println); } catch (IOException e) { e.printStackTrace(); } // recollir l'Stream en una List try { List<String> lines = Files.lines(Paths.get("lines.txt")).collect(Collectors.toList()); for(String line : lines) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); }

Exercici 5 - TopFiveScores

Fes un programa que accepti com a arguments el nom i la puntuació (score) d'un jugador. El programa emmagatzemarà en un fitxer els 5 scores més alts en ordre de major a menor. Així doncs, si l'score donat com a argument no està al top 5, no l'emmagatzemarà. En finalitzar l'operació, el programa mostrarà aquest Top Five per pantalla.

Exemple:

$ java top5 "James Gosling" 300 ** TOP 5 SCORE ** James Gosling 300 $ java top5 "Anders Hejlsberg" 500 ** TOP 5 SCORE ** Anders Hejlsberg 500 James Gosling 300 $ java top5 "Chris Lattner" 400 ** TOP 5 SCORE ** Anders Hejlsberg 500 Chris Lattner 400 James Gosling 300 $ java top5 "Brendan Eich" 200 ** TOP 5 SCORE ** Anders Hejlsberg 500 Chris Lattner 400 James Gosling 300 Brendan Eich 200 $ java top5 "Bjarne Stroustrup" 600 ** TOP 5 SCORE ** Bjarne Stroustrup 600 Anders Hejlsberg 500 Chris Lattner 400 James Gosling 300 Brendan Eich 200 $ java top5 "Guido van Rossum" 100 ** TOP 5 SCORE ** Bjarne Stroustrup 600 Anders Hejlsberg 500 Chris Lattner 400 James Gosling 300 Brendan Eich 200

JSON/XML

Instal·lar la llibreria FasterXML/Jackson

build.gradle plugins { id 'java' } sourceSets.main.java.srcDirs = [ "src/" ] repositories { mavenCentral() } dependencies { implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0' }

JSON d'exemple

{ "nombre": "Juan", "ciclo": { "titulo": "DAM", "curso": 2 }, "modulos": [ { "codigo": "M6", "nota": 9.8 }, { "codigo": "M8", "nota": 9.9 } ] }

Mapping classes per al JSON d'exemple

class Estudiante { public String nombre; public CicloFormativo ciclo; public List<Modulo> modulos; } class CicloFormativo { public String titulo; public int curso; } class Modulo { public String codigo; public float nota; }

JSON <-> String

readValue(String, Class<T>)

String jsonValue = "{\"nombre\": \"Juan\", \"ciclo\": { \"titulo\": \"DAM\", \"curso\": 2 }, \"modulos\": [ { \"codigo\": \"M6\", \"nota\": 9.8 }, { \"codigo\": \"M8\", \"nota\": 9.9 } ] }"; ObjectMapper objectMapper = new ObjectMapper(); Estudiante estudiante = objectMapper.readValue(jsonValue, Estudiante.class); System.out.println(estudiante.nombre); System.out.println(estudiante.ciclo.titulo + estudiante.ciclo.curso); System.out.println(estudiante.modulos.stream().map(m -> m.codigo + ": " + m.nota).collect(Collectors.joining("\n")));

writeValueAsString(Object)

Estudiante estudiante = new Estudiante(); estudiante.nombre = "Pepe"; estudiante.ciclo = new CicloFormativo(); estudiante.ciclo.titulo = "DAW"; estudiante.ciclo.curso = 1; estudiante.modulos = new ArrayList<>(); estudiante.modulos.add(new Modulo()); estudiante.modulos.add(new Modulo()); estudiante.modulos.get(0).codigo = "M2"; estudiante.modulos.get(0).nota = 7; estudiante.modulos.get(1).codigo = "M3"; estudiante.modulos.get(1).nota = 8.2f; ObjectMapper objectMapper = new ObjectMapper(); String jsonValue = objectMapper.writeValueAsString(estudiante); System.out.println(jsonValue);

JSON <-> File

readValue(File, Class<T>)

Estudiante estudiante = objectMapper.readValue(Paths.get("file.json").toFile(), Estudiante.class); System.out.println(estudiante.nombre); System.out.println(estudiante.ciclo.titulo + estudiante.ciclo.curso); System.out.println(estudiante.modulos.stream().map(m -> m.codigo + ": " + m.nota).collect(Collectors.joining("\n")));

writeValue(File, Object)

Estudiante estudiante = new Estudiante(); estudiante.nombre = "Juan"; // ... objectMapper.writeValue(Paths.get("file.json").toFile(), estudiante);

JSON <-> URL

readValue(URL, Class<T>

ObjectMapper objectMapper = new ObjectMapper(); Estudiante estudiante = objectMapper.readValue(new URL("https://gist.githubusercontent.com/gerardfp/b6b72efb17404d46bfc0a13200166167/raw/4864017a335d66a24e6250faabaeef111ca1ebc7/estudiante.json"), Estudiante.class); System.out.println(estudiante.nombre); System.out.println(estudiante.ciclo.titulo + estudiante.ciclo.curso); System.out.println(estudiante.modulos.stream().map(m -> m.codigo + ": " + m.nota).collect(Collectors.joining("\n")));

Exercici 6 - Agenda

Crea un programa que permeti emmagatzemar contactes a mode d'agenda. Les dades s'han d'emmagtzemar en un fitxer json.

El programa es podrà executar amb les següents opcions:

Exercici 7 - Library

Genera les classes necessàries per a emmagatzemar dades conformes amb aquest diagrama E/R. Crea objectes d'aquestes classes i emmagatzema'ls en un fitxer JSON.

De quina forma modelaries les dades per obtenir les respostes a aquestes peticions?

Exercici 8 - OpenAPI

Escull diverses APIs públiques i utilitza-les per a obtenir les seves dades. Hauràs de modelar almenys 6 respostes diferents.

https://github.com/public-apis/public-apis