Salta el contingut

5. Arxius separats per comes. CSV

1. Arxius CSV

Un fitxer de valors separats per comes (CSV) és un fitxer de text estàndard que utilitza una coma (,) per separar els valors. Cada línia del fitxer consisteix en un o més camps separats per comes. Cada camp pot o no estar tancat entre cometes dobles. A més, diversos formats utilitzen diferents caràcters com a separador, com el punt i coma (;) o el símbol de numeral (#).

El RFC 4180 defineix el format o les definicions d'un fitxer CSV o fitxer de text/csv.

El format CSV és útil per coses com:

  1. Senzill d'implementar i de llegir, a més de compatibilitat entre plataformes. Això és degut a que son fitxer de text pla.
  2. Compatibilitat: programes com Excel i Google Sheets permeten la manipulació d'aquest fitxer. Ademés la majoria de llenguatges moderns incorporen llibreries de manipulació d'aquest format
  3. Ocupa menys espai que els seus respectius JSON o CSV, degut a que les etiquetes sols apareixen un cop, en la linia de capçalera. S'ha convertit en l'estàndar de facte (no imposat per ningú, sinò per la pròpia comunitat) per a representar conjunts de dades per a IA i Big Data
El CSV és molt útil si les dades son simples i no son estructurades.
JSON
{"curs": [
{
    "hores": 6,
    "nom": "Accés a Dades",
    "nota": 8.45
},
{
    "hores": 3,
    "nom": "Programació de serveis i processos",
    "nota": 9
},
{
    "hores": 6,
    "nom": "Desenvolupament d'interfícies",
    "nota": 8
},
{
    "hores": 5,
    "nom": "Programació Multimèdia i dispositiud mòbils",
    "nota": 7.34
},
{
    "hores": 5,
    "nom": "Sistemes de Gestió Empresarial",
    "nota": 8.2
},
{
    "hores": 3,
    "nom": "Empresa i iniciativa emprenedora",
    "nota": 7.4
}
]}
XML
<curs>
    <modul>
        <nom>Accés a Dades</nom>
        <hores>6</hores>
        <qualificacio>8.45</qualificacio>
    </modul>
    <modul>
        <nom>Programació de serveis i processos</nom>
        <hores>3</hores>
        <qualificacio>9.0</qualificacio>
    </modul>
    <modul>
        <nom>Desenvolupament d'interfícies</nom>
        <hores>6</hores>
        <qualificacio>8.0</qualificacio>
    </modul>
    <modul>
        <nom>Programació Multimèdia i dispositiud mòbils</nom>
        <hores>5</hores>
        <qualificacio>7.34</qualificacio>
    </modul>
    <modul>
        <nom>Sistemes de Gestió Empresarial</nom>
        <hores>5</hores>
        <qualificacio>8.2</qualificacio>
    </modul>
    <modul>
        <nom>Empresa i iniciativa emprenedora</nom>
        <hores>3</hores>
        <qualificacio>7.4</qualificacio>
    </modul>
</curs>
Text Only
1
2
3
4
5
6
7
Nom,Hores,Nota
Accés a Dades,6,8.449999809265137
Programació de serveis i processos,3,9.0
Desenvolupament d'interfícies,6,8.0
Programació Multimèdia i dispositiud mòbils,5,7.340000152587891
Sistemes de Gestió Empresarial,5,8.199999809265137
Empresa i iniciativa emprenedora,3,7.400000095367432
El CSV no és adequat en dades estructurades
JSON
{
"persona": {
    "nom": "Joan",
    "edat": 30,
    "adreça": {
    "carrer": "Carrer Gran",
    "ciutat": "Barcelona",
    "codi_postal": "08001"
    }
},
"hobbies": ["lectura", "escalada", "viatjar"],
"contactes": [
    {
    "nom": "Marta",
    "telefon": "123456789",
    "relacio": "amic"
    },
    {
    "nom": "Pau",
    "telefon": "987654321",
    "relacio": "company"
    }
]
}
XML
<persona>
    <nom>Joan</nom>
    <edat>30</edat>
    <adreça codi_postal="08001">
        <carrer>Carrer Gran</carrer>
        <ciutat>Barcelona</ciutat>
    </adreça>
    <hobbies>
        <hobby>lectura</hobby>
        <hobby>escalada</hobby>
        <hobby>viatjar</hobby>
    </hobbies>
    <contactes>
        <contacte relacio="amic">
            <nom>Marta</nom>
            <telefon>123456789</telefon>
        </contacte>
        <contacte relacio="company">
            <nom>Pau</nom>
            <telefon>987654321</telefon>
        </contacte>
    </contactes>
</persona>

Text Only
1
2
3
4
5
6
nom,edat,carrer,ciutat,codi_postal,hobby,relacio_contacte,nom_contacte,telefon_contacte
Joan,30,Carrer Gran,Barcelona,08001,lectura,,,
Joan,30,Carrer Gran,Barcelona,08001,escalada,,,
Joan,30,Carrer Gran,Barcelona,08001,viatjar,,,
Joan,30,Carrer Gran,Barcelona,08001,,amic,Marta,123456789
Joan,30,Carrer Gran,Barcelona,08001,,company,Pau,987654321
Hem aplanat les dades, cosa que porta molta redundància i poca claredat

2. Separador

En cas que el símbol utilitzat com a separador aparegui dins dels valors, és una bona idea tancar el contingut entre cometes. Es pot veure un exemple de fitxer CSV aquí:

Text Only
1
2
3
4
5
6
7
Chevrolet Chevelle Concours (sw);0;8;350.0;165.0;4142.;11.5;70;US
Ford Torino (sw);0;8;351.0;153.0;4034.;11.0;70;US
Plymouth Satellite (sw);0;8;383.0;175.0;4166.;10.5;70;US
AMC Rebel SST (sw);0;8;360.0;175.0;3850.;11.0;70;US
Dodge Challenger SE;15.0;8;383.0;170.0;3563.;10.0;70;US
Plymouth Cuda 340;14.0;8;340.0;160.0;3609.;8.0;70;US
Ford Mustang Boss 302;0;8;302.0;140.0;3353.;8.0;70;US

3. Processament

La manera de processar un fitxer CSV en Java és:

  1. Obrir el fitxer com a fitxer de text per a la lectura. Hem de llegir línia per línia, ja que cada línia és un registre. Llegir una línia en una variable de tipus String.
  2. Processar els registres individuals:
    1. Podem separar cada camp. Una bona opció és utilitzar el mètode split(char) de la classe String. Obtinguem un array de cadenes amb els valors dels camps individuals.
    2. Processar cada valor de camp segons les necessitats.

Atenció

És una bona idea començar a utilitzar les classes abstractes Files i Paths. Aquestes classes milloren l'ús de la classe File i les seves classes derivades, oferint mètodes útils que ens permeten realitzar operacions ràpides amb menys línies de codi. Per exemple, la següent línia, a partir del filename, l'obre i després llegeix tot el fitxer, retornant una llista amb les línies separades en cada element de la col·lecció.

Java
List<String> lines=Files.readAllLines(Paths.get(filename));

Més informació a:

Text Only
1
2
- [Files](https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/nio/file/Files.html)
- [Paths](https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/nio/file/Paths.html)

4. Exercici proposat

A partir de la classe mòdul vista anteriorment:

  1. Afig un constructor que a partir de una línia del CSV cree el objecte mòdul
  2. Afig un mètode a la clàsseque convertisca el objecte en un línia CSV
  3. Crea un funcío que guarda tot el array de curs a un arxiu CSV
  4. Compara el tamany del fitxer respecte al JSON o XML
  5. Crea una funció que llig el CSV i genere els objectes a l'array

Ampliació

A aules tens un dataset d'entrenament de models de IA. Es trata de wine_reviews, opinions i caarcteríístiques sobre molts vins del món (el dataset pesa >= 50MB). Les característiques que tenim son (primera línea del csv):

Text Only
1
2
3
,country,description,designation,points,price,
province,region_1,region_2,taster_name,
taster_twitter_handle,title,variety,winery

Eixa primer coma al principi és que hi ha una primera columna que és el id de cara review, per tant podria ser perfectament id,country,description,designation,points,price, province,region_1,region_2,taster_name, taster_twitter_handle,title,variety,winery

Es demana:

  1. Carrergar-lo en memòria. Quina estructura trobes que és la òptima?
  2. Quantes reviews hi han en total
  3. Localitza i genera un llistat de:
  4. Aquelles reviews que els falta alguna columna
  5. Aquelles columnes que els falta alguna data en alguna fila