Inicio Persistencia en ficheros
Entrada
Cancelar

Persistencia en ficheros

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()

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:

  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í:

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 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

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:

Esta entrada está licenciada bajo CC BY 4.0 por el autor.