Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Leggere file zip in un... Flash

Usare la libreria Fzip per manipolare archivi compressi con ActionScript 3
Usare la libreria Fzip per manipolare archivi compressi con ActionScript 3
Link copiato negli appunti

All'interno di Actionscript 3 è stata introdotta una classe che ha acceso la fantasia di molti sviluppatori: si tratta della classe ByteArray, che come si può facilmente intuire dal nome è in grado di contenere una serie di byte. Si dà il caso che qualsiasi dato è rappresentato da un insieme di byte, quindi si può facilmente immaginare come questa classe apra nuovi orizzonti per lo sviluppo in Flex 2 (e in Flash 9).

«I possibili utilizzi della classe ByteArray includono:

  • creazione di protocolli personalizzati per connettersi ad un server,
  • scrittura del proprio codificatore/decodificatore di URL,
  • scrittura del proprio programma AMF/Remoting,
  • ottimizzazione dei dati utilizzando i datatype »

(tradotto dal Manuale di Flex 2)

In questo articolo però non andremo ad analizzare la classe ByteArray in sè, ma un'altra classe realizzata sfruttando ByteArray. Stiamo parlando della classe FZip, realizzata da Claus Wahlers e Max Herkender: FZip è una classe creata in Actionscript 3 in grado di leggere i file contenuti in un archivio di tipo Zip.

I possibili utilizzi di questa classe sono abbastanza vari, sul sito di riferimento è stato realizzato un esempio che apre un archivio contenente mille icone in formato PNG (scaricato dal sito www.famfamfam.com) e le mostra mano a mano nel filmato SWF.

Purtroppo l'unica operazione che la classe FZip può fare (almeno al momento) è quella di aprire un file Zip e leggerne il contenuto, che potremo poi mostrare nel filmato SWF. Il Flash Player non può scrivere file sul server, quindi, qualora volessimo estrarre il contenuto dell'archivio in una directory del nostro sito dovremmo comunque affidarci a linguaggi esterni come ad esempio PHP. Dunque la classe FZip non è in grado di estrarre "fisicamente" i file di un archivio utilizzando il solo flash player, e allo stesso modo non è in grado di creare un archivio zip.

Per quanto siano due carenze decisamente "importanti" (anche se alla prima si può ovviare tramite l'utilizzo di linguaggi server-side), la possibilità attualmente offerta dalla classe è comunque interessante, specialmente se la consideriamo nell'ottica della realizzazione di un pannello di amministrazione da consegnare ad un cliente: supponiamo di avere una photogallery e voìerla rendere aggiornabile dal cliente. Normalmente dovremmo fargli uploadare tutte le foto una per una: grazie a questa classe potremmo fargli uploadare solamente il file zip con le foto da aggiungere, creando lo script che si occupi di andare a recuperare le foto e le mostri correttamente all'interno del filmato. Un po' come avviene nel già citato esempio disponibile sul sito degli sviluppatori. Questo chiaramente è solo uno dei possibili utilizzi!

Vediamo allora come utilizzare questa libreria: per prima cosa ricostruiremo l'esempio; è già disponibile il codice sorgente, ma costruire il proprio filmato da zero e analizzare i vari passaggi è sicuramente più produttivo per l'apprendimento della classe!

Utilizzo della classe con Flex

Per prima cosa scarichiamo il file fzip.zip e scompattiamo i file in una cartella a nostra scelta. La cartella dove estrarremo i file conterrà le cartelle "docs", "src" e "tools". In particolare ci interessa la cartella "src", che contiene la classe vera e propria, ed è anche la directory in cui creeremo il nostro progetto Flex.

Avvio di Flex e creazione del progetto

Nota: nel prosieguo dell'articolo, i testi e le immagini faranno riferimento al Flex Builder 2 (di cui è disponibile una trial di 30 giorni sul sito Adobe), è comunque possibile utilizzare un qualsiasi altro editor o IDE e poi compilare i file con il Flex 2 SDK, anch'esso disponibile sul sito Adobe come download gratuito.

Apriamo il Flex Builder e selezioniamo dal menu la voce File>New>Actionscript Project. Si aprirà un pannello dove andremo ad impostare il nome del progetto e la relativa directory: come nome inseriamo "FZip", mentre per quanto riguarda il percorso togliamo il segno di spunta alla voce "Use default location" e scegliamo invece come directory (utilizzando il pulsante "Browse") la cartella src che abbiamo appena scompattato.

Figura 1. Il pannello per la creazione di un nuovo progetto Actionscript

Pannello Flex per un nuovo progetto

Premiamo quindi il tasto "Finish". All'interno del Flex Builder apparirà un file, con nome "FZip.as" e contenente il seguente codice:

package {
  import flash.display.Sprite;
  public class FZip extends Sprite {
    public function FZip() { }
  }
}

Per prima cosa, modifichiamo il codice: non possiamo avere nel nostro file una classe di nome FZip, dato che questo è il nome della libreria che utilizzeremo; cambieremo quindi il nome della classe del nostro file in "Test_FZip", così

package {
  import flash.display.Sprite;
  public class Test_FZip extends Sprite {
    public function Test_FZip() { }
  }
}

Se salviamo il file, noteremo che il Flex Builder ci mostra l'errore:

Esempio di output su console

"A file found in a source-path 'FZip' must have the same name as the class definition inside the file 'Test_FZip'.
FZip.as	FZip"

Significa semplicemente che il file deve avere lo stesso nome della classe che contiene, il nostro file invece si chiama ancora FZip.as; sarà allora sufficiente rinominarlo in Test_FZip.as (è possibile farlo direttamente dall'interfaccia di Flex Builder, basta un click destro sul nome del file nel pannello "Navigator", quindi scegliere "Rename").

Figura 2. Script e nome del file dopo le modifiche

Interfaccia Flex Builder

Stesura del codice

Siamo finalmente pronti per scrivere le prime righe del nostro codice. Per prima cosa dobbiamo importare la classe FZip per poterla puoi utilizzare all'interno del nostro progetto; posizioniamoci allora sulla seconda riga e aggiungiamo il codice per importare le classi necessarie nel nostro esempio.

import deng.fzip.FZip;
import deng.fzip.FZipFile;

Una caratteristica molto interessante del Flex Builder è la sua capacità di inserire automaticamente gli import necessari, infatti un'alternativa all'inserimento manuale di queste due righe di codice era portarsi all'interno della funzione Test_FZip e scrivere ad esempio:

var zip:FZip
var file:FZipFile

Il Flex Builder avrebbe automaticamente inserito in cima allo script le due righe che abbiamo inserito manualmente. Nel prosieguo dell'articolo sfrutteremo questa caratteristica del Flex Builder, che ovviamente vale anche per le classi di default del Flash Player.

Abbiamo deciso di replicare l'esempio disponibile sul sito della classe, quindi vediamo cosa fa questo esempio: apre il file zip, carica le icone in esso contenute, le mostra mano a mano sullo stage e mostra un campo di testo che informa su quante siano le icone caricate fino a quel momento. Avremo quindi bisogno di:

  • un oggetto FZip (per caricare il file zip)
  • un oggetto FZipFile (per esaminare il file caricato)
  • una variabile per il conteggio dei file
  • una variabile da impostare come "controllo" per quando tutti i file sarano stati caricati
  • un campo di testo dove mostrare il numero di file caricati
  • una variabile da utilizzare per sapere se siamo alla fine dell'archivio o se sono presenti altri file

Dichiariamo allora queste variabili. Solitamente le dichiarazioni delle variabili che verranno utilizzate all'intrno del filmato vengono scritte all'inizio della classe, in questo modo:

public class FZipTest extends Sprite{
  private var zip:FZip;
  private var file:FZipFile
  private var testo:TextField;
  private var file_attuale:uint = 0;
  private var conta:uint = 0;
  private var fatto:Boolean = false;

Abbiamo creato le nostre variabili:

  • zip conterrà la classe FZip e si occuperà di caricare il file,
  • file esaminerà l'archivio zip,
  • testo sarà il campo di testo che conterrà i messaggi,
  • file_attuale verrà utilizzata in un ciclo per stabilire quale sia il file interno all'archivio zip che si sta esaminando,
  • conta verrà utilizzata come variabile per controllare quando si raggiunge la fine dell'archivio,
  • fatto verrà impostata su true una volta finito di esaminare il file zip scelto.

Abbiamo già assegnato un valore alle variabili file_attuale, conta e fatto, valori che modificheremo durante l'esecuzione del filmato

Notiamo come grazie allo strong typing abbiamo già impostato il tipo di dati che le variabili andranno a contenere, inoltre se abbiamo scritto manualmente il codice avremo anche visto che, come accennato in precedenza, una volta completata la riga relativa alla variabile testo, il Flex Builder abbia aggiunto automaticamente tra i package da importare flash.text.TextField.

Passiamo alla scrittura del codice che si occuperà di analizzare il file zip... prima però dobbiamo procurarci un file zip da esaminare! Per l'esempio consiglio di utilizzare la citata raccolta di icone. Posizioniamo il file nella stessa cartella del file "Test_FZip.as". Nell'esempio, per comodità il file è stato rinominato "icone.zip".

Per prima cosa creeremo il campo di testo, che sarà l'unico elemento presente sullo stage prima del caricamento delle icone, inoltre imposteremo il codice necessario per rilevare gli eventi, che nel nostro caso saranno l'apertura del file zip e la conclusione dell'analisi dei file in esso contenuti. Esaminiamo il codice necessario, che poi andremo a spiegare riga per riga.

public function FZipTest() {
  // Creazione del campo di testo
  testo = new TextField();
  // Impostazione delle proprietà del campo di testo
  testo.height = 20;
  testo.width = 576;
  // Disegno del campo di testo sullo stage
  addChild(testo);
  // creazione dell'oggetto FZip
  zip = new FZip();
  // Associazione degli eventi di apertura e di fine
  // esame dell'archivio alle relative funzioni
  zip.addEventListener(Event.OPEN, Apri);
  zip.addEventListener(Event.COMPLETE, Completo);
  // Caricamento dell'archivio
  zip.load(new URLRequest("icone.zip"))
}

Mentre il codice per importare la classe URLRequest sarà aggiunto automaticamente quando scriveremo il codice per il caricamento del file zip, dovremo aggiungere all'inizio del codice la riga

import flash.events.Event

necessaria per utilizzare gli eventi che abbiamo impostato (Event.OPEN ed Event.COMPLETE). In generale possiamo facilmente notare quando manca un package o una funzione nel progetto, perchè Flex quando proviamo a salvare il file restituisce l'errore:Access of undefined property Event.

A proposito, noteremo che Flex ci restituirà anche i seguenti errori

  • Access of undefined property Apri
  • Access of undefined property Completo

Niente di preoccupante: il programma ci sta solo indicando che abbiamo impostato nei listener degli eventi due funzioni che non sono presenti nel filmato. Le creeremo a breve.

I commenti all'interno del codice dovrebbero essere sufficienti a spiegare le operazioni eseguite: per prima cosa creiamo il campo di testo, ne impostiamo la larghezza a 576 pixel e l'altezza a 20, quindi lo posizioniamo sullo stage con il comando addChild. Dopodiché creiamo l'oggetto FZip e impostiamo i due eventi, indicando quali funzioni richiamare (Apri all'apertura del file, Completo quando l'esame dell'archivio sarà finito). Come ultima cosa indichiamo, tramite l'utilizzo di un oggetto URLRequest, il file da analizzare ("icone.zip").

Creazione delle funzioni

Come possiamo intuire, il codice "fondamentale" per il caricamento delle icone all'interno del filmato si troverà all'interno delle funzioni che dobbiamo realizzare; il codice scritto finora infatti si limita ad inserire nel filmato un campo di testo e apre il file zip, ma mancano tutte le azioni relative all'elaborazione del file zip.

Tali operazioni dovranno iniziare quando il file sarà stato aperto, per cui creiamo la funzione Apri e impostiamo al suo interno il listener per un EnterFrame: in questo modo saremo sicuri che le azioni associate all'EnterFrame verranno eseguite solo quando il file è stato aperto correttamente; ricordiamo che l'EnterFrame fa sì che un determinato numero di azioni venga eseguito in maniera continua, fino a quando l'EnterFrame stesso non sarà fermato o eliminato (cosa che faremo in seguito).

private function Apri():void{
  addEventListener(Event.ENTER_FRAME, esamina);
}

private function esamina():void{
  // azioni
}

Ora, una volta aperto il file, sarà associata all'EnterFrame la funzione esamina: non ci resta che inserire in quest'ultima funzione i comandi necessari a caricare le icone e a mostrarle sullo stage. Per scrivere le azioni corrette esaminiamo prima la struttura del file zip, esplorandolo con il nostro software abituale.

La struttura del file zip

Un buono script dovrebbe essere in grado di analizzare il file ZIP indipendentemente dalla sua struttura, o comunque agire in base al tipo di dati che trova all'interno dell'archivio. In questo caso però vogliamo semplicemente provare la classe e abbiamo un solo file ZIP da analizzare, per cui possiamo fare uno strappo alla regola e basare il nostro script sul file da analizzare. Il file contiene i seguenti elementi:

  • Una cartella "icons"
  • Un file "readme.html"
  • Un file "readme.txt"

Dentro alla cartella "icons" troviamo i tutti i file PNG. Quindi il nostro script dovrà caricare all'interno del file SWF i soli file PNG contenuti nella cartella "icons", ignorando il resto del contenuto dello ZIP. Traduciamo questo ragionamento in Actionscript.

La funzione "esamina"

Abbiamo già predisposto la funzione esamina, inseriamo al suo interno il codice.

private function esamina(evt:Event):void{
  // Se non siamo all'ultimo file dell'archivio
  if(zip.getFileCount() > file_attuale){
    // Ricaviamo il file attuale
    file = zip.getFileAt(file_attuale);
    // Controlliamo che sia un PNG presente nella cartella ICONS
    if(file.filename.indexOf("icons/") == 0 && file.filename.indexOf(".png") != -1) {
      // Lo carichiamo...
      var loader:Loader = new Loader();
      loader.loadBytes(file.content);
      // ...e lo posizioniamo sullo stage
      loader.x = 18 * (conta % 32);
      loader.y = 18 * Math.floor(conta / 32) + 20;
      addChild(loader);
      // Incrementiamo il numero di icone caricate
      conta++;
      // Mostriamo il numero di icone caricate nel campo di testo
      testo.text = conta + " icone caricate";
    }
    // Passiamo al file successivo
    file_attuale++;
  } else {
    // Se invece siamo all'ultimo file
    if(fatto){ // Se l'esame dell'archivio è stato completato
      // Rimuoviamo l'EnterFrame
      removeEventListener(Event.ENTER_FRAME,esamina)
      // Mostriamo nel campo di testo la dicitura per il caricamento completato
      testo.text = "Tutte le icone sono state caricate"
    }
  }
}

I commenti dovrebbero aiutare a capire il codice, che è sostanzialmente semplice. Per prima cosa controlliamo di non essere giunti all'ultimo file dell'archivio, paragonando il numero restituito dal metodo getFileCount della libreria FZip - che ci restituisce il numero di file contenuti nell'archivio - e il numero di file esaminati fino a quel momento (memorizzato nella variabile file_attuale, che incrementiamo ad ogni file esaminato); qualora vi siano ancora file da esaminare, andiamo a ricavare le informazioni sul file attuale (grazie al metodo getFileAt) e controlliamo che sia un PNG situato nella cartella icons: se lo è, creiamo un nuovo oggetto di tipo loader, lo posizioniamo sullo stage (basandoci sul valore della variabile conta, che viene incrementata ad ogni icona caricata) e vi carichiamo dentro l'icona. Ad ogni icona caricata andiamo anche ad incrementare il valore contenuto nel campo di testo con nome testo.

Quando invece non ci saranno altri file da esaminare, controlleremo che la variabile fatto sia impostata a true: se lo è, andremo a rimuovere il listener ed imposteremo il testo "Tutte le icone sono state caricate".

Se osserviamo il codice del nostro esempio nel complesso noteremo che manca ancora una cosa: la variabile fatto al momento non viene impostata a true in nessun punto del codice; questo perchè non abbiamo ancora creato la funzione Completo, che avrà il seguente codice:

private function Completo(evt:Event):void{
  fatto = true;
}

Tale funzione verrà richiamata quando lo script avrà finito di caricare l'archivio.

Attenzione: di caricare, non di esaminare! Questo vuol dire che l'evento onComplete sarà eseguito molto prima che tutte le icone siano state caricate e mostrate nel filmato: per questo noi impostiamo nella funzione esamina la rimozione del listener e il messaggio di caricamento completato, controllando comunque che i dati che abbiamo ricavato fossero basati sull'intero archivio.

Test del filmato

Ora che il codice è praticamente completo, potremmo testare il nostro filmato. Usiamo però il condiziale, perchè con il Flash Player 9 avremmo una "brutta sorpresa" se non eseguissimo una modifica alle impostazioni del player, infatti

Se proviamo a compilare il nostro filmato (premendo "Ctrl+F11", selezionando la voce di menu Run>Run Test_Fzip oppure utilizzando il pulsante "play" in verde nella barra degli strumenti del Flex Builder), otteremmo come risultato nel browser il filmato completamente vuoto.

Prima di spendere tempo prezioso a cercare un bug insesistente proviamo ad eseguire il file SWF direttamente dal Flash Player: portiamoci nella cartella dove abbiamo scompattato la classe FZip all'inizio dell'articolo, quindi dentro alla cartella "src" troveremo delle nuove directory (create dal Flex Builder): entriamo nella cartella "bin" ed avviamo il file "Test_FZip.swf".

Figura 3. La finestra di errore del Flash Player

Finestra di errore

Il Flash Player 9 ci informa che per i settaggi di sicurezza il filmato SWF non può accedere all'archivio zip. A questo punto per testare il nostro filmato abbiamo due possibilità

  • Uplodare SWF e Zip su un web server
  • Modificare le impostazioni del player

Il primo metodo è quello più immediato: online i permessi di sicurezza del player sono diversi da quelli in locale e quindi il filmato funzionerebbe correttamente.

La configurazione delle impostazioni di sicurezza del player esula dallo scopo di questo articolo, quindi per il secondo metodo ecco due link che possono aiutare a comprendere meglio i problemi della sicurezza in locale e i settaggi del player

Riporto comunque la soluzione che ho adottato, per chi volesse testare il filmato e non avesse uno spazio web su cui uplaodare i file: ho aperto il file "AdobeBridgeTrust.cfg" contenuto nella cartella:

{cartella_di_windows}system32MacromedFlashFlashPlayerTrust

e ho aggiunto il percorso della cartella dove erano situati i miei file di test della libreria.

Risolto il problema possiamo finalmente vedere il nostro filmato in azione.

Figura 4. Screenshot di una parte del filmato: vediamo come le icone siano troppo grosse

Screenshot di una parte del filmato

Appare evidente che le icone sono troppo grandi, questo perchè vengono ridimensionate in base alla dimensione del file SWF che nel nostro caso occupa tutta l'area del browser; essendo molto grandi tra l'altro, non staranno tutte e 1000 all'interno dello spazio a disposizione. Possiamo risolvere anche questo utilizzando il seguente codice:

stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;

Nota: il Flex Builder aggiungerà automaticamente le linee per l'importazione delle classi StageAlign e StageScaleMode se scriveremo a mano il codice, altrimenti sarà necessario aggiungere ad inizio file l'importazione delle classi file.display.StageAlign e flash.display.ScaleMode

Questo codice altro non fa che specificare l'allineamento degli elementi del filmato (in alto a sinistra in questo caso) ed impostare il NO_SCALE, che permette di evitare che gli elementi si ridimensionino al variare delle dimensioni del filmato.

Figura 5. Dopo le modifiche le icone mantengono la loro dimensione

Screenshot di una parte del filmato

In questo caso le icone non risultano ingrandite, ed entreranno tranquillamente all'interno del filmato SWF.

Il codice che dovremmo avere alla fine dei passaggi seguiti è questo.

Volendo possiamo cambiare il numero di icone mostrate per ogni riga andando a modificare il valore 32 nelle azioni di posizionamento dell'oggetto loader (loader.x e loader.y).

Utilizzo della classe in Flash

La classe è utilizzabile anche con la Flash 9 Public Alpha, nel nostro esempio però il codice va leggermente modificato per poterlo inserire su un fotogramma della timeline. Modificando il codice in questo modo.

Potremmo utilizzarlo anche all'interno di Flash. Ricordiamo che è necessaria la Flash 9 Public Alpha (reperibile negli Adobe Labs) dato che la libreria è scritta in Actionscrpt 3 e tale linguaggio sarà inserito appunto nella versione 9 di Flash.

Conclusioni

Abbiamo visto come con un numero piuttosto ridotto di righe di codice (meno di 80) sia possibile estrarre un migliaio di file da un archivio Zip, utilizzando sia il Flex Builder 2, sia la Public Alpha di Flash 9. La classe FZip offre anche altre possibilità di utilizzo, ma sicuramente l'estrazione di file con successivo caricamento all'interno di un file SWF è l'uso più comune che si può fare di questa libreria, che rappresenta decisamente un esempio molto interessante di quanto sia possibile realizzare con il ByteArray di Actionscript 3!

Ti consigliamo anche