MokaByte
Numero 20 - Giugno 1998
|
|||
|
|
||
Marco Molinari |
|||
Il programma prevede due modalità di funzionamento: da linea di comando e grafica. Per questo la classe estende Frame (una finestra dotata di titolo e di bordo) ed è dotata di questi metodi:
Il cuore del programma è costituito dalle due procedure split() e join(), che rispettivamente dividono e uniscono il file. Se questi metodi non fossero dichiarati static non potrebbero essere chiamati senza istanziare la classe stessa, ovvero quando si utilizza il programma dalla linea di comando.
L'algoritmo (se di algoritmo si può parlare) di split() è semplice: in input si ha il nome di un file e la grandezza in kbytes che ogni file spezzato dovrà avere; in output si hanno i file spezzati, chiamati nomeoriginale.00, .01 ecc. Il funzionamento è elementare: si prende il pezzo successivo del file di partenza e lo si scrive nel file di output particolare fino a che si raggiunge la grandezza voluta del file di output; allora si chiude quel file di output e se ne apre un altro; si continua così fino a terminare il file di partenza.
In Java i file si gestiscono con le classi File, FileInputStream e FileOutputStream: File rappresenta un puntatore al file su cui si possono fare operazioni come vedere se esiste, cambiarne il nome e cancellarlo. FileInputStream e FileOutputStream prendono come parametro un File e rappresentano i flussi di dati da e verso quel File: i loro metodi fondamentali sono quelli ereditati da InputStream e OutputStream, ovvero letture e scritture di byte e array di byte. Alternativamente i due FileStream possono prendere direttamente una String; nel codice si è istanziato un File solo quando ce ne fosse effettivamente bisogno, cioè quando era necessario vedere se il file esisteva e quando bisognava sapere quanto era lungo il file. Nel codificare bisogna prestare attenzione, perchè si rischia di produrre un codice di una lentezza mortificante. Il pericolo è di usare i metodi che leggono o scrivono un byte alla volta; agendo così bisogna armarsi di molta pazienza, il codice funziona ma impiega parecchio tempo.
Ecco come sarebbe
il codice (size è la grandezza del file di output in un certo momento,
chunks è la grandezza finale di ogni pezzo; length è la lunghezza
del file originale):
FileInputStream fis = new FileInputStream(source);Il metodo read() ritorna il prossimo byte letto, -1 quando il file di input è finito.
while (length > 0) {
FileOutputStream fos = new FileOutputStream(source+"."+Integer.toString(i));
int size = 0;while ( (chunks > size) && ((singoloByte = fis.read()) != -1) ){
fos.write(singoloByte);
size++;
}length -= chunks;
fos.close();
i++;}
fis.close();
FileInputStream fis = new FileInputStream(new BufferedInputStream(source));Questa idea è alla base di tutto il sistema di I/O di Java e permette di aggiungere solo le caratteristiche volute a una certa stream.
while (length > 0) {
FileOutputStream fos = new FileOutputStream(new BufferedOutputStream(source+"."+Integer.toString(i)));
[...]
Purtroppo però
la situazione migliora ma non di molto: la soluzione ottima è usare
i metodi delle FileStreams che leggono e scrivono array di byte ogni volta.
Decidiamo di leggere e scrivere 1024 byte alla volta e in input chiediamo
il numero di kbyte che deve comporre ogni file di output invece del numero
preciso di byte; per l'aumento di prestazione che si ricava è un
buon compromesso.
FileInputStream fis = new FileInputStream(source);Il metodo utilizzato qui è read(byte[], int, int) che riempie il byte[] e ritorna il numero di byte effettivamente letti, -1 se il file è finito.
int amount; // contiene a ogni passaggio il numero di byte letti
byte[] b = new byte[bufSize];while (length > 0) {
FileOutputStream fos = new FileOutputStream(source+"."+Integer.toString(i));
int size = 0;while ( (chunks > size) && ((amount = fis.read(b,0,bufSize)) != -1) ){
fos.write(b,0,bufSize);
size++;
}length -= chunks*bufSize;
fos.close();
i++;}
fis.close();
L'operazione di join() è l'esatto inverso di split(); vuole il nome dei pezzi di file senza estensione ".n"; si aprono uno a uno i file di input e si riversano i loro contenuti nel file di output. Utilizza la lettura e la scrittura di array di byte come split() e non risolve il problema di sapere quanti file ci sono in input: quando non ci saranno più file di input viene generata un'eccezione che viene ignorata.In Java 1.1 sono state aggiunte nuove classi di I/O, facenti capo a Reader e Writer. Il motivo principale per questo cambiamento è stato l'internalizzazione (i vecchi Stream non supportano bene i caratteri Unicode a 16 bit); infatti Reader, Writer e derivati servono solo a gestire flussi di caratteri, quindi non servono al nostro scopo.
File outputFile = new File(destination);
FileOutputStream fos = new FileOutputStream(outputFile);
byte c[] = new byte[bufSize];try {
for (int i = 0; true; i++) {
FileInputStream fis = new FileInputStream(destination+"."+i);
int amount;while ((amount = fis.read(c, 0, bufSize)) != -1) {
fos.write(c, 0, amount);
}fis.close();
}
} catch (FileNotFoundException e) {
} // lo facciamo continuare finchè ci sono file da unirefos.close();
Per la gestione degli eventi si è restati sui vecchi e poco eleganti metodi di Java 1.0 per motivi di compatibilità. Il metodo action() e la sua fila di if si occupano di questo. handleEvent() serve invece solo alla chiusura della finestra.
Per quanto riguarda
il costruttore, esso è chiamato solo nella "modalità grafica"
e si occupa di istanziare i vari oggetti. Invece di rovinarsi la vita correndo
dietro al troppo sfuggevole GridBagLayout, si è preferito usare
quattro Panel messi nella finestra in un GridLayout di 4 righe e una colonna.
I Panel hanno come layout standard il FlowLayout, che mette semplicemente
i componenti in riga disegnadoli con la loro grandezza naturale, al contrario
di quanto sarebbe accaduto mettendo i componenti direttamente nel GridLayout.
setLayout (new GridLayout(4,1));Il programma ha fatto il suo dovere, dividendo il file sotto Windows 95 e ricomponendolo sotto Mac; inoltre sotto Linux non c'è neanche bisogno di caricare XWindows per farlo funzionare se ci si accontenta di usarlo dalla shell.Panel p1 = new Panel();
p1.add(browse);
p1.add(filename);
add(p1);Panel p2 = new Panel();
p2.add(messages);
add(p2);Panel p3 = new Panel();
p3.add(chunkSize);
p3.add(sizeOfChunks);
add(p3);Panel p4 = new Panel();
p4.add(split);
p4.add(join);
add(p4);
MokaByte Web 1998 - www.mokabyte.it MokaByte ricerca nuovi collaboratori. Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@mokabyte.it |