18 articoli nella categoria Corso Java

Andrea Pastore 19/03/2020 0

18. Programmazione concorrente

Prima di introdurre questo agomento dobbiamo capire come funzionano i moderni processori: vediamo la foto di un’architettura di un processore intel:

Vediamo che è composto da varie parti: i core (le unità che di elaborazione, il codice che scriviamo viene elaborato da loro) una piccola memoria interna (da non confondersi con la memoria RAM, che non risiede nel processore) e poi una scheda video. Il numero di processi che può essere eseguito contemporaneamente dipende dal numero di core, quindi il processore mostrato in figura può eseguire quattro processi contemporaneamente. Il sistema operativo ha il compito di assegnare le risorse ad un processo: tra le altre cose deve decidere a quale processore assegnare il processo, controllare che non si blocchi, aggiornare la coda dei processi in attesa di essere eseguiti e molto altro ancora. Un processo resta in esecuzione per una frazione di secondo, poi se ha esaurito il compito viene terminato, altrimenti viene reinserito nella coda dei processi che in attesa di essere eseguiti.

I programmi moderni, a meno che non siano programmi molto piccoli sono composti da tanti processi in esecuzione sul proprio computer, ognuno con un compito. Un esempio è rappresentato dai browser web, come Firefox: l’architettura di questo browser prevede attualmente che ci sia un processo deputato a mostrare l’interfaccia (che mostra ad esempio le tab aperte) e altri processi che gestiscono le tab.

 

Lo scheduler del sistema operativo

Per stabilire quale processo debba essere eseguito ogni sistema operativo dispone di un software chiamato scheduler, che gestisce la coda dei processi tenendo conto di una serie di fattori: priorità, stato del processo e molti altri. Se il sistema operativo è progettato per gestire hardware in grado di gestire più thread contemporaneamente (ovvero tutti gli strumenti che utilizziamo maggiormente oggi: computer, telefonini, ma anche centraline di oggetti di uso comune come l’automobile) il suo ruolo si complica perché deve tenere conto anche degli altri thread. Ad esempio un thread di un processo potrebbe dover aspettare che un altro thread termini l’esecuzione.

 

La programmazione concorrente in Java

Java mette a disposizione due modi per creare processi concorrenti: la prima possibilità consiste nella creazione di una classe che estende la classe Thread, la seconda consiste nella creazione di una classe che implementa l’interfaccia Runnable. Le differenze dal punto di vista del codice sono minime, creiamo due classe Trhead_A e Trhead_B per vederle:

 

Classe che estende la classe Thread

public class Thread_A extends Thread {

private int contatore;



public Thread_A() {

this.contatore = 0;

}



public void run() {

this.contatore ++;

System.out.println("Trhead A: contatore= "+contatore);

}

}

 

Classe che implementa l’interfaccia Runnable

public class Thread_B implements Runnable{

private int contatore;

public Thread_B() {

this.contatore = 0;

}

@Override

public void run() {

this.contatore++;

System.out.println("Thread B: contatore="+contatore);

}

}

Notiamo che entrambe le classi hanno un metodo public void run(). Questo è un metodo necessario in quanto descrive le operazioni che deve fare il Thread. Nei nostri esempi qui sopra i thread incrementano un contatore e lo stampano.

 

Lanciare un Thread

A seconda del metodo che abbiamo scelto, i Thread si lanciano in due modi diversi. Se abbiamo scelto di creare le classi che estendono la classe Thread, come nel nostro esempio del Trhead_A, scriveremo:

Thread_A t  = new Thread_A();

t.start();

Se usiamo una classe che estende l’interfaccia Runnable creeremo prima un’istanza di quella classe, e un Trhead a partire da quella:

	Thread_B rc = new Thread_B();

Thread t1 = new Thread(rc);

t1.start();

Nota: in entrambi i casi per far partire un thread bisogna invocare il metodo start().

 

Assegnare la priorità ad un thread

È possibile impostare la priorità di un thread con il metodo setPriority. Java prevede per la priorità un valore da 1 a 10, se non lo impostiamo manualmente la priorità assegnata di default è 5. La classe Trhead dispone di tre costanti che sono:

MAX_PRIORITY = 10

MIN_PRIORITY = 1

MEDIUM_PRIORITY  = 5

Se ad esempio voglio impostare la priorità massima scriverò:

	t.setPriority(Thread.MAX_PRIORITY);

Per impostare altri valori sulla scala da 1 a 10 possiamo usare i numeri.

 

Mettere in pausa un thread

Può capitare di dover fermare un thread per un certo intervallo di tempo (ad esempio perché deve ripetere una determinata operazione dopo un tempo prestabilito), per questo Java mette a disposizione diversi metodi. Sleep, join e yeld.

 

sleep

prende in input il numero di millisecondi durante i quali il thread deve stare in pausa. Per invocarlo correttamente bisogna utilizzare il costrutto try .. catch, perché dobbiamo prevenire il fatto che un altro thread provi a chiamare il thread dove abbiamo invocato il metodo sleep:

	try {       	  		   

t1.sleep(10);

     } catch (InterruptedException ex) {

       // handle the error

       System.out.println("si è verificata un'eccezione");

     }

 

join

questo metodo serve a mettere in attesa il thread su cui è invocato fino a quando altri trhead al suo interno non abbiano terminato l’esecuzione. Supponiamo di avere un thread t1 che crea un thread t2 per eseguire un’operazione. L’istruzione:

	t2.sleep(10);

metterà in attesa il thread t1 fino a quando t2 non avrà terminato la sua esecuzione.

 

yeld

È un metodo statico che suggerisce allo scheduler di mettere in pausa il tread corrente per lasciare spazio ad altri. Viene invocato in questo modo:

	Thread.yield();
Leggi tutto

Andrea Pastore 19/03/2020 0

17. L’operatore Lambda

L’operatore lambda è stato introdotto in Java 8 ed è rappresentato dal simbolo -> e  consente di velocizzare alcune operazioni. Supponiamo di avere il seguente codice:

		ArrayList<String> stringhe = new ArrayList<>();

stringhe.add("Andrea");

stringhe.add("Antonio");

stringhe.add("Alessandro");

stringhe.add("Alfonso");

supponiamo ora di voler stampare tutti i nomi presenti in questo ArrayList: se volessimo usare un metodo tradizionale potremmo scrivere

		for(int i = 0; i<4; i++) {

System.out.println(stringhe.get(i));

}

vediamo ora come fare la stessa cosa con l’operatore lambda:

		stringhe.forEach((String s) -> System.out.println(s));

come vediamo è molto più sintetico: sul nostro array invochiamo il metodo forEach che applica l’espressione lambda a tutto l’array.

Con gli operatori lambda possiamo anche applicare dei filtri. Ad esempio supponiamo di voler stampare solo le stringhe che hanno valore Andrea. In modo tradizionale sarebbe:

		for(int i = 0; i<4; i++) {

if(stringhe.equals("Andrea")) {

System.out.println(stringhe.get(i));

}

}

vediamo invece con l'operatore lambda:

		stringhe.stream().filter(s->s.equals("Andrea")).forEach((s) -> 				System.out.println(s));

Abbiamo applicato il metodo stream per prendere tutti gli oggetti e poi il metodo filter per inserire il filtro che ci interessava, infine abbiamo usato di nuovo il metodo forEach per stampare.

Leggi tutto

Andrea Pastore 19/03/2020 0

16. Il Java Collection Framework

Un framework è un insieme di classi, librerie o funzioni che aiutano i programmatori a sviluppare il proprio programma più velocemente. Il Java Collection Framework è una collezione di classi e interfacce sviluppata direttamente dai creatori del linguaggio Java. Le classi del Java Colection Framwork implementano strutture dati più evolute rispetto ad un array, che possono essere utilizzate in situazioni specfiche. Per Collection intendiamo una classe (o un’interfaccia che deve essere usata per creare una classe) che dispone di metodi per gestire un insieme di dati (ad esempio un insieme di stringhe, un insieme di interi ma anche dati più complessi, per esempio tipi di dati creati da noi). Esiste un’interfaccia chiamata Collection che viene estesa da tutte le interfacce del Java Collection Framework.

 

Le interfacce del Java Collection Framework sono:

  • List
  • Set
  • Map
  • Iterator
  • Queue

Per ogni interfaccia, tranne Iterator, abbiamo un’implementazione:

  • ArrayList
  • HashMap
  • HashSet
  • PriorityQueue (e molte altre, maggiori informazioni nel paragrafo dedicato)

Nota: a differenza dell’array che è un tipo di dato primitivo, quando vogliamo usare le strutture di dati presenti nel framework dobbiamo importarle.

 

Il tipo di dato generico

Tutte le classi del Java collection Framwork utilizzano una caratteristica di Java: i tipi generici (generics in inglese). Questo consiste nello specificare di volta in volta

quando si crea una determianta classe che tipo di dato si vuole utilizzare. Vediamo un esempio con l’ArrayList, la prima classe di questo framework che vedremo nella prossima pagina.

		ArrayList arr = new ArrayList<>();

La riga qui sopra definisce un ArrayList di stringhe. Il tipo di dato viene specificato subito dopo il nome della classe all’interno dei simboli <>. Questo simbolo va ripetuto anche nel costruttore, in questo caso vuoto. Per ora non soffermiamoci su questo punto, più avanti nel corso del libro capiremo come mai viene ripetuto e cosa può essere inserito al suo interno.

 

Gli ArrayList

La classe ArrayList è l’implementazione dell’interfaccia List, consente di memorizzare gli elementi un po’ come un array, ma con alcune funzionalità in più. Come per gli array dobbiamo specificare il tipo di dato, ma si fa in modo diverso:

		ArrayList arr = new ArrayList<>();

La riga qui sopra definisce un ArrayList di stringhe.

Nota: non abbiamo fatto menzione ai numeri, perché la dimensione di un ArrayList non è fissa. Appena lo creiamo sarà vuoto, poi crescerà man mano che inseriremo elementi.

Per inserire un elemento nell’ArrayList si usa il metodo Add. Il codice sottostante inserisce nell’ArrayList la parola “ciao”:

		arr.add("ciao");

Per recuperare un elemento dall’arrayList usiamo il  metodo get. Il codice qui sotto memorizza all’interno di una variabile (in questo caso Stringa) il valore alla posizione 0 dell’arrayList:

		//recuperiamo ora un elemento

String s = arr.get(0);

Per eliminare un elemento dall’arrayList usiamo il metodo remove. Il seguente codice  rimuoverà l’elemento alla posizione 0 dell’ArrayList:

		arr.remove(0);

Quando un elemento viene eliminato, la dimensione dell’arrayList si riduce, e gli elementi successivi indietreggiano di una posizione.

Per conoscere la dimensione di un ArrayList usiamo il metoto size, il seguente codice memorizza all’interno di una variabile la dimensione attuale dell’ArrayList

		int size = arr.size();

 Per sapere se un elemento è presente nel nostro ArrayList possiamo usare il metodo contains:

arr.contains(“nomeStringa”)

l’utilizzo più tipico è quello all’interno di un costrutto if:

		if(arr.contains(“nomeStringa”)) {

// eseguiamo del codice se nomeStringa è presente

}

Quando l’arrayList contiene tipi di dati complessi (esempio una classe che abbiamo definito) il metodo prenderà in input un oggetto di quel tipo e confronterà le locazioni di memoria.

 

Le mappe (HashMap)

Finora abbiamo visto strutture di dati che consentono un accesso basato sulla posizione: ad esempio per prendere un determinato elemento da un array dobbiamo usare il seguente codice:

		String s = arrayInt[0];

Se invece non sappiamo la posizione del nostro elemento, dobbiamo scorrere tutto l’array fino a quando non lo troviamo. Un modo alternativo di memorizzare gli elementi è quello di associare una chiave ad ognuno di essi. Ad esempio memorizzo una stringa e le assegno un nome per identificarla, ad esempio memorizzo un codice fiscale e come nome scrivo "mioCodiceFiscale" Questa stringa contenente il mio codice fiscale sarà immediatamente raggiungibile cercando la parola chiave "mioCodiceFiscale", invece di scorrere un array.

Creiamo adesso la nostra prima mappa, dobbiamo utilizzare (e quindi importare) la classe Hashmap. Nota: dobbiamo importare anche l’interfaccia Map.

import java.util.Map;

import java.util.HashMap;

Map<String,String> m = new HashMap<>();

Quando creiamo una mappa dobbiamo specificare due tipi di dati: quello della chiave

e quello dell'elemento che vogliamo memorizzare. Nel nostro caso, supponendo di voler memorizzare dei codici fiscali, avremmo come tipo di dato String per la chiave (ed codiceFiscaleGiovanni) e String per il valore (ES RSSGNN90S05A592N)

Per inserire un elemento in una mappa si usa il metodo put, che prenderà in input una coppia nome valore del tipo specificato al momento della creazione della mappa.

	m.put("CodiceFiscaleGiovanni", "RSSGNN90S05A592N");

Per recuperare un elemento dalla mappa si usa invece il metodo get. Continuando con il nostro esempio, per prendere il codice fiscale che abbiamo inserito prima scriveremo:

	String codiceFiscale = m.get("CodiceFiscaleGiovanni");

Nota: i nomi devono essere univoci, nell’esempio qui sopra abbiamo inserito nella mappa una chiave chiamata  CodiceFiscaleGiovanni, non possiamo inserire altre chiavi con lo stesso nome, altrimenti il valore precedente con la stesa chiave verrà sovrascritto.

Se infatti dopo aver scritto i codici sopra scriveremo:

 	m.put("CodiceFiscaleGiovanni", "RSSGNN74S09A592K");

Il valore precedentemente memorizzato verrà sovrascritto e quando proveremo a recuperare questo dato dalla mappa otterremo "RSSGNN74S09A592K"

Per rimuovere un elemento dalla mappa si usa il metodo remove che ha come parametro la parola chiave che abbiamo inserito al momento della creazione di quell’elemento. Ad esempio se voglio rimuovere il codice fiscale inserito sopra scriverò:

	m.remove("CodiceFiscaleGiovanni");

Facciamo ora un altro esempio: supponiamo di dover memorizzare i dati dei nostri utenti. Abbiamo una classe Utente che contiene i dati, e dobbiamo memorizzarli in una mappa. Il codice che scriveremo sarebbe questo:

Map<String,Utente> m = new HashMap<>();

Per inserire un oggetto scriveremo: 

	m.put("UtenteGiovanni", u);

Dove u è un oggetto di tipo utente.

 

Gli insiemi (HashSet)

Un insieme è un tipo di dato che non ammette duplicati, ovvero non possiamo inserire più di una volta la stessa chiave. Sugli insiemi possiamo eseguire le operazioni dell’insiemistica, ovvero l’intersezione, l’unione e cosi via. Per creare un insieme dobbiamo importare queste classi:

import java.util.Set;

import java.util.HashSet;

Creiamo il nostro primo insieme, che conterrà delle stringhe:

Set set = new HashSet<>();

Aggiungiamo i nostri primi elementi:

	set.add("a");

set.add("b");

Nota: gli insiemi non accettano duplicati. Se inseriamo ad esempio questo codice:

	set.add("c");

set.add("c");

nell’insieme troveremo comunque un solo elemento “c”.

 

Operazioni con gli insiemi

Per eseguire l’intersezione di due insiemi dobbiamo usare il metodo retainAll().

	set.retainAll(set2);

Questo metodo va invocato su un insieme e ha bisogno di un altro insieme come parametro ed eliminerà nell’insieme su cui è stato invocato tutti gli elementi che non fanno parte di set2.

Dati questi insiemi:

set1 = [A, B, C]

set2 = [A, D]

l’esecuzione del metodo retainAll con questi due insiemi porterà a questo insieme:

risultato = [A]

Per eseguire l’unione usiamo invece il metodo addAll()

	set.addAll(set2);

questo metodo aggiunge il contenuto dell’insieme passato come parametro all’interno dell’insieme su cui è invocato. Ovviamente se ci sono duplicati non troveremo due volte lo stesso valore.

Dati questi insiemi:

set1 = [A, B, C]

set2 = [A, D]

l’unione di questi insiemi porterà ad avere questo nuovo insieme:

risultato = [A, B, C, D]

 

Le code

Una coda (queue in inglese) è una struttura dati che si comporta proprio come una coda ad una cassa o ad un ufficio. I dati inseriti al suo interno sono ordinati in ordine di arrivo e verranno eliminati nello stesso ordine. Questo approccio si definisce FIFO (first in first out), ovvero il primo elemento che viene inserito nella coda sarà il primo ad uscire. Le code vengono utilizzate quando il programma che dobbiamo realizzare richiede di svolgere alcune operazioni in ordine di arrivo. Si pensi ad esempio ad un programma che gestisce le richieste di assistenza dei clienti: un tecnico che si libera deve sapere qual è la prossima richiesta di assistenza a cui deve lavorare. Questa situazione potrebbe essere gestita con una coda

 

Diversi tipi di code

Il tda coda cosi come descritto sopra è solo una base, sono stati sviluppati diversi tipi di code adatti a diverse esigenze. Vediamone le principali:

  • Coda a priorità
    Si tratta di una coda che aggiunge, all’approccio FIFO, una variante legata alla priorità di un elemento inserito.
  • Coda sincronizzata
    Si tratta di un tipo di coda utilizzato nella programmazione concorrente, ovvero quando più processi di un programma accedono contemporaneamente alla coda.

Esistono molti altri tipi di code, ma per i nostri fini didattici utilizzeremo un’implementazione delle code a priorità chiamata PriorityQueue, che in caso di priorità tutte uguali si comporterà esattamente secondo il principio FIFO, altrimenti terrà conto delle priorità.

		PriorityQueue queue = new PriorityQueue<>();	

Aggiungere un elemento nella coda

		queue.add("Lucia");

 

Rimuovere il prossimo elemento nella coda

Per rimuovere l’elemento primo in lista nella coda si usa il metodo remove. Il metodo restituisce l’oggetto rimosso  in una variabile.

		String elementoRimosso = queue.remove();

 

Conoscere il primo elemento della coda

In alcuni casi potremmo sapere qual è il prossimo elemento della coda, senza però rimuoverlo. In questi casi possiamo usare il metodo peek:

		String elemento = queue.peek();	

// conoscere la dimenzione di una coda

int size = queue.size();

 

Gli stack

Una pila (stack in inglese) è una struttura dati che si comporta in maniera opposta alla coda: il primo elemento ad essere inserito sarà il primo ad essere restituito. Immaginiamo una pila di libri: mettiamo l’uno sull’altro diversi libri, quando dobbiamo riprenderli per ordinarli il libro in cima sarà l’ultimo libro che abbiamo posto su di essa. Java mette a disposizione la classe Stack per implementare questa struttura dati.

 

Creiamo il nostro primo stack:

Come per gli altri elementi del Java Collection Framework dobbiamo specificare il tipo di dato, nel nostro caso String.

	Stack stack = new Stack<>();

 

Aggiungere elementi

Per aggiungere un elemento allo stack utilizziamo il metodo add:

	stack.add("Luca");

possiamo anche decidere dove inserirlo, specificando una posizione

	stack.add(2, "Antonio");

 

Rimuovere elementi

Per rimuovere elementi dallo stack si usa il metodo remove. Questo metodo richiede di specificare la posizione da rimuovere, questo ci consente di seguire la logica degli stack quando questa ci serve, mettendo come indice 0:

	String elementoRimosso = stack.remove(0);

Possiamo però decidere di non seguire questa logica e rimuovere un qualsiasi altro elemento.

 

Gli iteratori

Vediamo ora un altro importante elemento del java collection framework, la classe Iterator. Questa classe consente di iterare tutti gli elementi di una qualsiasi classe del java collection framework

Dispone di un metodo hasNext per sapere se ci sono ancora elementi, e del metodo next per recuperare il prossimo elemento.

Nota che l'iteratore non consente di tornare indietro, quando un elemento viene restituito non può essere richiesto nuovamente. L'iteratore invia tutti gli elementi una volta sola, quando restituisce l'ultimo elemento si è esaurito. Ne consegue che gli iteratori possono essere usati una volta sola.

Supponiamo di avere una variabile set che è un insieme contenente questi valori: [a, b, c, d, e, f, g, h, i]

possiamo creare un iteratore di questo insieme in questo modo

	Iterator it = set.iterator();

Come gli altri elementi del Java Collection Framework anche per gli iteratori bisogna specificare il tipo di dato tra i simboli <>. Il tipo di dato deve ovviamente coincidere con quello della classe su cui si invoca l'iteratore. Per scorrere tutti gli elementi dell’iteratore usiamo:

		 while(it.hasNext()) {

String elem = it.next();

System.out.println(elem);

}

Nell’esempio qui sopra stampiamo l’elemento, ma potremmo compiere le operazioni più disparate. 

L'iteratore può essere invocato su liste, set, code e altri elementi del java collection framework, ma non si può invocare direttamente su una mappa, perché è una collezione di elementi nome - valore. Per usarlo sulla mappa invochiamo il metodo keyset e che restituisce un insieme delle chiavi e poi invochiamo su di esso l'iteratore. Vediamo un esempio qui sotto, supponiamo di avere una mappa m con un certo numero di elementi.

		 Iterator it = m.keySet().iterator();

while(it2.hasNext()) {

String elem = it.next();

System.out.println(m.get(elem));

}
Leggi tutto

Andrea Pastore 19/03/2020 0

15. Le date in Java

Le date in Java sono memorizzate in oggetti appositi, che contengono il numero di secondi dal 01/01/1970. Ovviamente le date possono essere formattate in vari formati, ad esempio quello italiano che è gg/mm/aaaa, oppure quello inglese che è aaaa/mm/gg. Java mette a disposizione la classe Date per rappresentare le date e la classe Calendar per recuperare una data. Vediamo un esempio:

Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone( "Europe/Rome"),Locale.ITALY);

La creazione di un oggetto di tipo Calendar è un po’ particolare: viene invocato il metodo getInstance come mostrato sopra, che prende in input la zona  temporale che ci interessa e il formato della data. Fatto questo è possibile recuperare le informazioni sulla data, con la riga di codice sottostante:

Date dataOggi = calendar.getTime();

 

Stampare una data

Per stampare una data dobbiamo creare un oggetto di tipo DateFormat e poi invocare il suo metodo format, passandogli come parametro la data.

DateFormat dateFormat = DateFormat.getDateInstance (DateFormat.SHORT, Locale.ITALY);

System.out.println("data oggi: "+dateFormat.format(dataOggi));

Il metodo getDateInstance della classe DateFormat prende in input come primo parametro il tipo di visualizzazione, nel nostro caso DateFormat.SHORT, che indica la stampa classica della data, ovvero nel formato gg/mm/aaaa. Ovviamente il formato è dato anche dal secondo parametro: se avessimo scritto:

DateFormat dateFormat = DateFormat.getDateInstance (DateFormat.SHORT, Locale.ENGLISH );

System.out.println("data oggi: "+dateFormat.format(dataOggi));

Avremmo ottenuto una stampa nel formato inglese ovvero mm/gg/aa.

 

Creare una data da una stringa

Possiamo creare un oggetto di tipo date a partire da una stringa, grazie alla classe SimpleDateFormat, ad esempio:

String s = "01/01/2019";

Date initDate = new SimpleDateFormat("dd/MM/yyyy").parse (s);

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

System.out.println(formatter.format(initDate));

Il costruttore di SimpleDateFormat prende in input il formato della data in input, nel nostro caso abbiamo scritto dd/mm/yyyy. Questo codice, però, può provocare un’eccezione se la data inserita in input non è corretta. Per questo motivo dobbiamo gestirlo usando il costrutto try catch:

	try {

String s = "01/01/2019";

Date initDate = new SimpleDateFormat("dd/MM/yyyy").parse (s);

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

System.out.println(formatter.format(initDate));

} catch (ParseException e) {

e.printStackTrace();

}
Leggi tutto

Andrea Pastore 19/03/2020 0

14. I file in Java

Java mette a disposizione diverse classi per operare con i file. La prima classe che vediamo è la classe File, che consente di prendere informazioni sul file che vogliamo utilizzare, ad esempio per sapere se il file esiste, se possiamo scrivere e molto altro ancora. Un oggetto file si inizializza cosi:

	File f = new File("prova.txt");

in questo caso abbiamo usato solo il nome del file, significa che Java cercherà quel file nella cartella dove sta eseguendo. Se il file che desideriamo si trova in un altra cartella possiamo anche fornire un percorso assoluto, come in questo caso:

	File f = new File("/nomecartella/sottocartella/prova.txt");

Nota: per utilizzare questa classe dobbiamo importarla scrivendo:

import java.io.File;

 

Metodi della classe file

Vediamo quali sono i principali metodi della classe File:

exists() Restituisce true se il file esiste, false altrimenti
createNewFile() Crea il file. Bisogna gestire un’eccezione di tipo IOException che viene lanciata nel caso il file non possa essere creato
canRead() Restiuisce true se Java può leggere il file
canWrite() Restituisce true se Java può scrivere il file
isHidden() Restituisce true se il file è nascosto, false altrimenti
isFile() Restituisce true se il percorso indicato è effettivamente un file, false altrimenti
isDirectory() Restituisce true se il percorso è una cartella, false altrimenti
length() Restituisce la dimensione del file in byte (sigifica che per avere ad esempio i mb devi dividere il valore restituito da long per 1000000
getAbsolutePath() Stampa il percorso completo del file es C:/cartella/cartella... ecc
astModified(); Restituisce la data dell'ultima modifica in millisecondi dal 1970 (vedi il file helloDate per convertirli in una data tradizionale)

 

Scrivere su un file

Per scrivere su un file dobbiamo utilizzare la classe  la classe FileOutputStream, il cui costruttore prende in input  un oggetto di tipo file. La scrittura nel file avviene con il metodo write: questo metodo prende in input una sequenza di byte, quindi dobbiamo convertire la stringa in byte con un metodo apposito: getBytes().

Nota: la creazione dell'oggetto FileOutputStream deve essere gestita con il costrutto try / catch per gestre due tipi di eccezioni: FileNotFoundEsception (che può verificarsi se scriviamo un percorso di file errato) e IOException (che può verificarsi quando Java non riesce a scrivere nel file).


public static void main(String[] args) {

File f = new File("prova.txt");

FileOutputStream out = null; // lo inizializziamo a null perché va gestito nel try catch

try {

out = new FileOutputStream(f);

out.write("Ciao".getBytes());

System.out.println("Scrittura eseguita con successo!");

} catch (FileNotFoundException e) {

e.printStackTrace();

}

catch (IOException e) {

e.printStackTrace();

}

}

 

La modalità append

Ci sono casi in cui il file contiene già delle informazioni e non vogliamo perderle. Possiamo usare la modalità append, che aggiunge il testo alla fine del file. Per usare questa modalità al momento della creazione dell’oggetto FileInputStream dobbiamo specificare un secondo parametro, che riguarda appunto se usare o meno la modalità append. La stringa:

			out = new FileOutputStream(f);

diventa

			out = new FileOutputStream(f,true);

 

Leggere da un file

come per FileOutputStream anche la classe FileInputStream ha bisogno di un oggetto di tipo file, e la creazione dell'oggetto FileInputStream deve essere gestita con il costrutto try / catch per gestre due tipi di eccezioni: la prima è FileNoTfoundEsception che può esere generata dal costruttore e la seconda è IOException generato dal metodo read che si occupa di leggere materialmetne il file.

	public static void main(String[] args) {


File f = new File("prova.txt");

FileInputStream in = null;

try {

in = new FileInputStream(f);

/*

*  scriviamo ora il codice per la lettura del file: il seguente ciclo while legge il

*  codice carattere per carattere, si fermerà solo quando il metodo read nel while ha

*  dato risultato -1, che indica appunto la fine del file

*/

int i = 0;

while((i= in.read()) != -1) {

// read restuisce dei numeri interi che noi dobbiamo convertire in formato char (ovvero il

// singolo carattere, per fare questo usiamo un cast

// (char) i; è un cast, ovvero convertiamo la variabile i ad un valore diverso.

// Nota: non è sempre possibile fare i cast

char c = (char) i;

System.out.print(c);

}

} catch (FileNotFoundException e) {

e.printStackTrace();

}

catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

Nota: i metodi che abbiamo visto consentono di leggere file semplici (txt, csv oppure formati definiti da noi). Per leggere formati più elaborati, come ad esempio i file Excel, dobbiamo usare librerie apposite.

Leggi tutto

Cerca...