Persistència en fitxers
Path operations
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()
1
Path path = Paths.get("/ruta/al/fitxer/o/directori");
Exemples
1
2
3
4
5
6
7
8
9
10
11
12
// 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 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
1
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:
- Els fitxers que estan al DirectoriA i no estan al DirectoriB
- Els fitxers que estan al DirectoriB i no estan al DirectoriA
- Els fitxers que estan al DirectoriA i al DirectoriB, però en diferents rutes
- 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í:
1
2
3
4
5
6
7
8
9
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:
1
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:
1
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()
1
// escriure bytes a un fitxer OutputStream os = Files.newOutputStream(path); os.write(63); os.write(127); os.write(33);
read()
1
2
3
// llegir un byte d'un fitxer
InputStream is = Files.newInputStream(path);
int a = is.read();
1
2
3
4
5
// 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:
1
/carpeta/foto.jpg 1024 bytes
i el dividirà en aquests 4 arxius:
1
2
3
4
/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:
1
2
3
4
/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:
1
/carpeta/foto.jpg 1024 bytes
Orientat a caracters
UTF-8
First code point | Last code point | Byte 1 | Byte 2 | Byte 3 | Byte 4 | ||
---|---|---|---|---|---|---|---|
0000 | 0 | 007F | 127 | 0xxxxxxx | |||
0080 | 128 | 07FF | 2047 | 110xxxxx | 10xxxxxx | ||
0800 | 2048 | FFFF | 65535 | 110xxxxx | 10xxxxxx | 10xxxxxx | |
10000 | 65536 | 10FFFF | 1114111 | 110xxxxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
BufferedWriter / BufferedReader
write("A")
, escriu el codepoint del caracter “A” codificat amb UTF-8.
write(65)
, escriu el codepoint 65 codificat en UTF-8
1
2
3
4
5
6
7
8
9
// 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()
1
2
3
4
5
6
// llegir caracters
try (BufferedReader br = Files.newBufferedReader(Paths.get("file.txt"))){
char a = (char) br.read();
} catch (IOException e) {
e.printStackTrace();
}
readLine()
1
2
3
4
5
6
// 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()
1
2
3
4
5
6
// escriure un string
try {
Files.writeString(Paths.get("string.txt"), "This is a string");
} catch (IOException e) {
e.printStackTrace();
}
Files.write()
1
2
3
4
5
6
7
8
// 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()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
$ 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
1
2
3
4
5
6
7
8
9
10
11
12
13
plugins {
id 'java'
}
sourceSets.main.java.srcDirs = [ "src/" ]
repositories {
mavenCentral()
}
dependencies {
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0'
}
JSON d'exemple
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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>)
1
2
3
4
5
6
7
8
9
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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>)
1
2
3
4
5
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)
1
2
3
4
5
6
Estudiante estudiante = new Estudiante();
estudiante.nombre = "Juan";
// ...
objectMapper.writeValue(Paths.get("file.json").toFile(), estudiante);
JSON <-> URL
readValue(URL, Class<T>)
1
2
3
4
5
6
7
8
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:
add
1
myprogram add <contact\_name> <contact\_phone> <contact\_email>
Afegeix el contacte a l’agenda. Si el <contact_name> ja està a l’agenda, el sobreescriu.
del
1
myprogram del <contact\_name>
Elimina, si existeix, el contacte amb aquest <contact_name>.
list
1
myprogram list
Llista tots els contactes que hi ha emmagatzemats.
find
1
myprogram find <contact\_email>
Llista els contactes que tenen aquest <contact_email>.
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?
Llibres de cada autor (amb el gènere i el número de copies en cada biblioteca)
Llibres de cada biblioteca (amb el gènere i l’autor).
Biblioteques on trobem cada llibre (amb el gènere, l’autor i el número de còpies)
Autors de cada gènere.
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
Webgrafía: