vuoi
o PayPal
tutte le volte che vuoi
FileOutputStream outputStream = new
FileOutputStream(“output.dat”);
In entrambi i casi si utilizza il metodo int read() che legge un
carattere / byte per volta e restituisce un valore di tipo int. Tale
valore corrisponde al codice del carattere / byte letto oppure –1
se non ci sono più dati da leggere.
C'è questa distinzione tra percorso relativo e assoluto perchè
· dobbiamo sepre pensare che il software quando va in esecuzione
ha un contesto, il contesto sostanzialmente sarebbe un'area di
lavoro in cui il software sta già operando, quindi se vado a scrive
un'applicativo Java che legge da un file e salvo il mio file.java in
una cartella X, allora compilo il sorgent e se non cambiamo nulla
la compilazione fa si che dentro la cartella stesssa trovo anche
il .class, se quindi faccio tutto nel main abbiamo solo il sorgente
e il .class corrispettivo. Se invece voglio dire al software di
anadare a leggere il file, il percorso assoluto funziona sempre
poichè infatti va nel file system che p una componente del
sistema operativo, il sistema operativo gestisce infatti il file
systema che è un suo compoente, il file systema ha delle
primitive del tipo "apri una certa cartella", "crea questo file" etc...
e quindi può accedere al percordo assoluto indicato, il file system
traduce il percordo dato e ci conduce alla cartella esatta.
Potrei quindi pensare di dare sempre il percorso completo così da
non avere problemi, questo è però sbagliato perchè se nel codice
vado a scrivere il percorso assoluto, ad esempio posso dichiarare
una costante che pongo uguale al percorso, passo quindi il nome
del file come se fosse una costante e dò il percorso assoluto,
però così quando distribuisco il mio file, nel momento in cui
passo un programma a un'altra persona il file non verrebbe
trovato, potrei anche pensare di creare lo stesso percorso,
rimane il fatto che la parte C:\users\nomeutente\ è gestita dal
sistema operativo, in realtà potrebbe anche chi riceve il file
creare la cartella \nomeutente\ ma ha poco senso ma
soprattutto, almeno per windows, la prima parte è differente,
quindi in generale l'idea è che il percorso assoluto ha senso
soloper la macchina per cui è stato scritto.
ciò che è da fare in questo caso è ragionare con i percorsi relativi
o pattern relativi. Un percorso relativo è un percorso che esprime
la posizione di una risorsa, quindi di un file, rispetto alla
posizione da cui stiamo osservando, quindi se sto scrivendo un
software e lo posiziono nella cartella X, quando il mio software
andrà in esecuzione il suo contesto è la cartella X, che è la
cartella in cui il software vive e che vede direttamente, quindi in
questa cartella se creo un file di nome writer.java, per lui la sua
posizione relativa è la cartella X, quindi se all'interno del file .java
vado a specificare il nome del file prova.txt lui lo vede perchè è
nella sua stessa posizione relativa, qiundi il percorso relativo del
file prova.txt rispetto al chiamante che sarà il writer.java è
identico, quindi basta solo il nome del file.
Immaginiamo ora che nella cartella X ci sia una cartella che si
chiama media e all'interno di media ci sia il nuovo file nuovo.txt,
immaginiamo ora che il writer voglia leggere il file nuovo.txt, a
questo punto il nuovo nome diventerà ./media/nuovo.txt, questo
è il percorso relativo da writer.java alla risorsa che è nuovo.txt,
possiao inoltre dire che nell'ultimo percorso indicato il punto
iniziale è un simbolo che indica di partire dalla cartella attuale a
cui si trova, in realtà lo si può scrivere anche media/nuovo.txt,
funziona comunque.
Immaginiamo ora che il file nuovo.txt si trovi in una cartella
esterna a X, ad esempio immaginiamo che ci sia una cartella Y
che contiene la cartella X e il file nuovo.txt, in questo caso
abbiamo lo stesso ragionamento solo che invece di andare in
avanti verso media devo tornare indietro, per tornare indietro
scrivo ../nuovo.txt
Torniamo ora alla situazione in cui nuovo.txt è interno alla
cartella media, ora se viene condiviso il progetto e viene
condivisa la cartella X, ora senza modificare nulla il software
funziona anche sul dispositivi con cui è stata condivisa la cartella
perchè non è stato indicato il percorso assoluto. Questo è il
vantaggio dei percorsi relativi.
Se la risorsa a cui accediamo non sta all'interno del file syste
quindi è qualcosa di remoto allora non c'è altre possibilità oltre a
mettere il percorso assoluto, lì c'è il concetto di resource
identifier che è il percorso assoluto ma è assoluto rispetto a un
over the top.
quando puntiamo a una risorsa web esterna, quindi passiamo un
percorso esterno, c'è sempre un entità, nel caso di internet è un
DNS, che risolvono quel percorso assoluto e lo rendono
interpretabile a livello più universale.
I file di configurazione servono se voglio mantenere un percorso
assoluto, questo non verrà scritto hard coded sul mio software
perchè so che poi perderei la portabilità ma vado ad aggiungere
dettagli sul file, quindi magari mi segno un percorso relativo e
tutti i percorsi assoluti li scarico su un file di testo che uso come
file di configurazione.
In ambito web le cosw diventano più complesse perchè quando
eseguiamo un'applicazione stand lone, cioè sulla nostra
macchina, in qualche modo siamo all'interno di un'ambiente ben
definito
Il vantaggio dei buffer è che faccio meno letture
· Un BufferedReader permette di gestire un flusso tramite un
· buffer:
I dati vengono letti a blocchi dal flusso e memorizzati in un
· buffer (area di memoria).
Quando viene richiesto un nuovo dato prima si verifica la
· suadisponibilità nel buffer e, se non disponibile in memoria,
si legge un nuovo blocco.
Mette a disposizione il metodo readLine()il quale legge una riga e
la restituisce sotto forma di stringa
Per associare un file ad un BufferedReader:
· FileReader file = new FileReader(“nome-file”);
BufferedReader in = new BufferedReader(file);
BufferedReader in = new BufferedReader(new FileReader(“nome-
· file”));
Per leggere da un BufferedReader: in.readLine();
· La chiusura del bufferedReader automaticamente chiude il
· FileReader da cui sta leggendo
La classe PrintWriter mette a disposizione i metodi void print() e
· void println() utilizzabili con qualunque tipo di parametro
(stringa, intero, reale, ecc.).
Si può creare un nuovo oggetto PrintWriter a partire da un Writer,
· in particolare da un FileWriter. PrintWriter f = new PrintWriter
(new FileWriter(“nome-file”) );
CSV:
· In un generico testo non c'è alcuna corrispondenza tra quello che
c'è scritto nelle righe nemmeno a livello strutturale, infatti
possono esserci lettere, numeri etc..., l'informazione ha senso se
viene strutturata, infatti nel mondo dei basi di dati si creano le
tabelle. Il prelievo dei dati è difficile se l'informazione è inserita in
maniera no strutturata. Qaundo abbiamo a che fare con file di
testo la struttura o semistruttura la si può stabilire usando dei
caratteri di separazione. Il CSV è un file in cui abbiamo qualcosa
di questo tipo:
matricola, nome, cognome, data
1010, Antonio, Blue, 1-2-1
2015, Michi, Verdi, 1-1-1
la prima riga si chiama header e può essere omessa purchè
abbia lo stesso numero di virgole di quello che ci sta sotto.
La struttura viene fuori dal fatto che quando lo salvo con
estensione CSV, se vado a leggerlo ome se fosse un CSV, la
prima cosa che il mio porgramma fa è chiedermi se il file ha un
header, se così fosse allora della prima riga conta solo le virgole
e la scarta, poi comincia a leggere i file, capisce che il primo dato
è un intero, poi c'è una virgola, poi una stringa, poi una virgola e
così via, vede se in ogni riga il numero di virgole coincide con
quelle del header e se così fosse allora è conforme, se c'è
un'anomalia il file diventa non leggibile..
Comma-separated è uno standard così definito, tuttavia il fatto
della comma non è una regola fissa, infatti possiamo usare ad
esempio il punto-e-virgola per dividere i caratteri, oppure gli
spazi o i tab, l'importante è che il separatore, una volta scelto,
sia asottato su tutte le righe.
Ora, se immaginassi di voler prendere la matricola in tutte le
righe, vado a prendere il primo elemento della riga prima che ci
sia il primo separatore, devo quindi prendere la riga e scomporla
sulla base del separatore, si parla di tokenization
La classe StringTokenizer e’ definita nel package java.util. Un
· oggetto StringTokenizer separa una stringa in sottostringhe dette
token. Per default, il tokenizer separa la stringa ad ogni spazio. Il
costruttore StringTokenizer richiede come parametro la stringa
da separare. Ciascuna chiamata al metodo nextToken()restituisce
il token successivo.
String.split Serve per dividere una stringa sulla base di un regex
· e non un separatore. Un regex è una regular expression che i
rappresenta una stringa tipica, un modello di stringa che ci
permette di identificare una particolare caratteristica di una
stringa
StringBuilder Esso è pensato come una sequenza mutabile di
· caratteri, quindi una sequenza in cui possiamo fare qualsiasi
modifica e senza avere il problema di ricreare l'oggetto. Quando
si legge dal file avremo sempre la situazione in cui leggiamo da
file e creiamo una stringa con quello che abbiamo letto, quindi
faremo tante operazioni di append sulla stringa, se usiamo la
concatenazione di stringhe normale ha un costo, se usiamo lo
stiringBuilder che ha il metodo appenda risparmiamo molto
tempo a livello di costo computazionale, risparmiamo quindi
risorse
StringBuilder e StringBuffer sono identici con gli stessi metodi,
· c'è però la solita differenza nel caso in cui la risorsa, quindi la
stringa fosse condivisa tra più processi, se quella stringa può
essere manipolata da due sottoprocessi del programma che
scrivono su stringBuilder, allora usare StrigBuilder è pericoloso
perchè esso non è sincronizzato, cioè non e pronto a gestire
conflitti tra tread diversi che accedono contemporaneamente. Il
funzionamento è duale a ciò che fa il sistema operativo