Esempio di ByteArray: lettura di un file zipAdobe AIR 1.0 e versioni successive In questo esempio viene illustrato come leggere un file zip semplice contenente vari file di tipi diversi. A tale scopo, è sufficiente estrarre dati pertinenti dai metadati per ciascun file, decomprimere ciascun file in un ByteArray e scrivere il file sul desktop. La struttura generale di un file zip si basa sulle specifiche fornite da PKWARE Inc., riportate in http://www.pkware.com/documents/casestudies/APPNOTE.TXT. In primo luogo sono presenti un'intestazione file e dati file per il primo file nell'archivio zip, seguiti da una coppia 'intestazione file e dati file per ciascun file aggiuntivo (la struttura dell'intestazione file verrà descritta in seguito). In secondo luogo, il file zip include facoltativamente un record di descrizione dei dati (di solito quando il file zip di output viene creato in memoria anziché salvato sul disco). Sono quindi presenti diversi elementi opzionali aggiuntivi: intestazione di decrittazione dell'archivio, record dei dati extra dell'archivio, struttura di directory centrale, record di fine della directory centrale in formato Zip64, localizzatore di fine della directory centrale in formato Zip64 e record di fine della directory centrale. Il codice in questo esempio è scritto solo per analizzare i file zip che non contengono cartelle, non prevede record di descrizione dei dati e ignora ogni tipo di informazione che segue gli ultimi dati dei file. Il formato dell'intestazione per ciascun file è il seguente:
L'intestazione del file è seguita dai dati del file veri e propri, che possono essere compressi o non compressi, a seconda del flag del metodo di compressione. Il valore de flag è 0 (zero) se i dati del file non sono compressi, 8 se sono compressi mediante l'algoritmo DEFLATE oppure hanno un valore diverso se è stato usato un altro algoritmo di compressione. L'interfaccia utente per questo esempio è costituita da un'etichetta e un'area di testo (taFiles). L'applicazione scrive le seguenti informazioni nell'area di testo per ciascun file incontrato nel file zip: il nome del file, la dimensione compressa e quella non compressa. Il seguente documento MXML definisce l'interfaccia utente per la versione Flex dell'applicazione: <?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="init();">
<mx:Script>
<![CDATA[
// The application code goes here
]]>
</mx:Script>
<mx:Form>
<mx:FormItem label="Output">
<mx:TextArea id="taFiles" width="320" height="150"/>
</mx:FormItem>
</mx:Form>
</mx:WindowedApplication>
L'inizio del programma effettua le seguenti operazioni:
In Flex, il codice del programma viene avviato nel metodo init(), che viene chiamato come gestore creationComplete per il tag mx:WindowedApplication dell'elemento principale. // for Flex
private function init():void
{
Il programma viene avviato aprendo il file zip in modalità di lettura (READ). zStream.open(zfile, FileMode.READ); Imposta quindi la proprietà endian di bytes su LITTLE_ENDIAN, a indicare che nell'ordine dei byte dei campi numerici il byte meno significativo è il primo. bytes.endian = Endian.LITTLE_ENDIAN; Successivamente, un'istruzione while() avvia un ciclo che continua fino a che la posizione corrente nel flusso di file è maggiore o·uguale alla dimensione del file. while (zStream.position < zfile.size)
{
La prima istruzione all'interno del ciclo legge i primi 30 byte del flusso di file nel valore bytes di ByteArray. I primi 30 byte costituiscono la parte di dimensione fissa dell'intestazione del primo file. // read fixed metadata portion of local file header
zStream.readBytes(bytes, 0, 30);
In seguito, il codice legge un valore intero (signature) dai primi byte dell'intestazione di 30 byte. La definizione del formato ZIP consente di specificare che la firma per ogni intestazione file è costituita dal valore esadecimale 0x04034b50; se la firma è diversa, ciò significa che il codice è stato spostato al di là della parte file del file zip e che non ci sono altri file da estrarre. In quel caso il codice esce dal ciclo while anziché attendere la fine dell'array di byte. bytes.position = 0;
signature = bytes.readInt();
// if no longer reading data files, quit
if (signature != 0x04034b50)
{
break;
}
La parte seguente del codice legge il byte di intestazione alla posizione di offset 8 e memorizza il valore nella variabile compMethod. Questo byte contiene un valore che indica il metodo di compressione utilizzato per il file. Sono consentiti diversi metodi di compressione, tuttavia in pratica quasi tutti i file zip utilizzano l'algoritmo di compressione DEFLATE. Se il file corrente è compresso mediante l'algoritmo DEFLATE, il valore di compMethod è 8; se il file non è compresso, compMethod sarà 0. bytes.position = 8;
compMethod = bytes.readByte(); // store compression method (8 == Deflate)
Dopo i primi 30 byte è presente una parte dell'intestazione di lunghezza variabile che contiene il nome del file ed eventualmente un campo aggiuntivo. Nella variabile offset è memorizzata la dimensione di questa parte. La dimensione viene calcolata aggiungendo la lunghezza del nome file e del campo extra, letta dall'intestazione agli offset 26 e 28. offset = 0; // stores length of variable portion of metadata
bytes.position = 26; // offset to file name length
flNameLength = bytes.readShort(); // store file name
offset += flNameLength; // add length of file name
bytes.position = 28; // offset to extra field length
xfldLength = bytes.readShort();
offset += xfldLength; // add length of extra field
In seguito, il programma legge la parte di lunghezza variabile dell'intestazione del file per il numero di byte archiviati nella variabile offset. // read variable length bytes between fixed-length header and compressed file data
zStream.readBytes(bytes, 30, offset);
Il programma legge il nome del file dalla parte a lunghezza variabile dell'intestazione e lo visualizza nell'area di testo insieme alle dimensioni del file compresso e non compresso (originale). // Flash version
bytes.position = 30;
fileName = bytes.readUTFBytes(flNameLength); // read file name
taFiles.appendText(fileName + "\n"); // write file name to text area
bytes.position = 18;
compSize = bytes.readUnsignedInt(); // store size of compressed portion
taFiles.appendText("\tCompressed size is: " + compSize + '\n');
bytes.position = 22; // offset to uncompressed size
uncompSize = bytes.readUnsignedInt(); // store uncompressed size
taFiles.appendText("\tUncompressed size is: " + uncompSize + '\n');
// Flex version
bytes.position = 30;
fileName = bytes.readUTFBytes(flNameLength); // read file name
taFiles.text += fileName + "\n"; // write file name to text area
bytes.position = 18;
compSize = bytes.readUnsignedInt(); // store size of compressed portion
taFiles.text += "\tCompressed size is: " + compSize + '\n';
bytes.position = 22; // offset to uncompressed size
uncompSize = bytes.readUnsignedInt(); // store uncompressed size
taFiles.text += "\tUncompressed size is: " + uncompSize + '\n';
L'esempio legge il resto del file dal flusso del file in bytes per la lunghezza specificata dalla dimensione compressa, sovrascrivendo l'intestazione del file nei primi 30 byte. La dimensione compressa è accurata anche se il file non è compresso, in quanto in quel caso la dimensione compressa del file è uguale a quella non compressa. // read compressed file to offset 0 of bytes; for uncompressed files
// the compressed and uncompressed size is the same
zStream.readBytes(bytes, 0, compSize);
Successivamente, nell'esempio, il file compresso viene decompresso e viene chiamata la funzione outfile() per scriverlo nel flusso di file di output. Vengono quindi trasmessi a outfile() il nome del file e l'array di byte contenente i dati del file. if (compMethod == 8) // if file is compressed, uncompress
{
bytes.uncompress(CompressionAlgorithm.DEFLATE);
}
outFile(fileName, bytes); // call outFile() to write out the file
La parentesi graffa di chiusura indica la fine del ciclo while, del metodo init() e del codice dell'applicazione, ad eccezione del metodo outFile(). L'esecuzione torna all'inizio del ciclo while e continua l'elaborazione dei byte seguenti nel file zip, mediante l'estrazione di un altro file oppure terminando l'elaborazione del file zip se l'ultimo file è stato elaborato. } // end of while loop } // for Flex version, end of init() method and application La funzione outfile() apre un file di output nella modalità WRITE sul desktop, attribuendo ad esso il nome fornito dal parametro filename. I dati del file vengono quindi scritti dal parametro data al flusso di file di output (outStream) e il file viene chiuso. // Flash version
function outFile(fileName:String, data:ByteArray):void
{
var outFile:File = File.desktopDirectory; // destination folder is desktop
outFile = outFile.resolvePath(fileName); // name of file to write
var outStream:FileStream = new FileStream();
// open output file stream in WRITE mode
outStream.open(outFile, FileMode.WRITE);
// write out the file
outStream.writeBytes(data, 0, data.length);
// close it
outStream.close();
}
private function outFile(fileName:String, data:ByteArray):void
{
var outFile:File = File.desktopDirectory; // dest folder is desktop
outFile = outFile.resolvePath(fileName); // name of file to write
var outStream:FileStream = new FileStream();
// open output file stream in WRITE mode
outStream.open(outFile, FileMode.WRITE);
// write out the file
outStream.writeBytes(data, 0, data.length);
// close it
outStream.close();
}
|
|