Ejemplo de ByteArray: Lectura de un archivo .zipAdobe AIR 1.0 y posterior Este ejemplo muestra cómo leer un archivo .zip sencillo que contiene varios archivos de diversos tipos. Para realizarlo, se extraen los datos pertinentes de los metadatos para cada archivo, se descomprime cada archivo para ponerlo en un ByteArray y se escribe el archivo en el escritorio. La estructura general de un archivo .zip se basa en la especificación de PKWARE Inc., que se mantiene en http://www.pkware.com/documents/casestudies/APPNOTE.TXT. Primero hay una cabecera de archivo y datos de archivo para el primer archivo individual del archivo .zip, seguido de un par de cabecera-datos de archivo para cada archivo adicional. (La estructura de la cabecera de archivo se describe más adelante). A continuación, el archivo .zip puede incluir como opción un registro de descriptor de datos (generalmente al crear el archivo zip en la memoria, más que al guardarlo en un disco). A continuación vienen varios elementos opcionales más: cabecera de descifrado del archivo comprimido, registro de datos adicionales del archivo comprimido, estructura del directorio central, registro de fin del directorio central Zip64, localizador de fin del directorio central Zip64, y registro de fin del directorio central. El código en este ejemplo se escribe para que sólo se analicen los archivos zip que no contengan carpetas y no espera que haya registros de descripción de datos. Pasa por alto toda la información que haya después del último dato del archivo. El formato de la cabecera de archivo para cada archivo es el siguiente:
Después de la cabecera del archivo vienen los datos del archivo, que pueden estar comprimidos o sin comprimir, según el indicador de método de compresión. El indicador será 0 (cero) si los datos están sin comprimir, u 8 si los datos están comprimidos con el algoritmo DEFLATE, u otro valor para otros algoritmos de compresión. La interfaz de usuario para este ejemplo consta de una etiqueta y un área de texto (taFiles). La aplicación escribe la información siguiente en el área de texto para cada archivo que encuentra en el archivo .zip: el nombre del archivo, el tamaño comprimido y el tamaño sin comprimir. El siguiente documento MXML define la interfaz de usuario para la versión Flex de la aplicación: <?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>
El principio del programa realiza las siguientes tareas:
En Flex, el código del programa empieza en el método init(), al que se llama como controlador de creationComplete para la etiqueta raíz mx:WindowedApplication. // for Flex
private function init():void
{
El programa empieza por abrir el archivo .zip en modo READ (lectura). zStream.open(zfile, FileMode.READ); A continuación define la propiedad endian de bytes en LITTLE_ENDIAN para indicar que el orden de bytes de los campos numéricos es con el byte menos significativo primero. bytes.endian = Endian.LITTLE_ENDIAN; Seguidamente, la sentencia while() inicia un bucle que continúa hasta que la posición actual en la secuencia de archivos sea superior o igual al tamaño del archivo. while (zStream.position < zfile.size)
{
La primera sentencia del bucle lee los 30 primeros bytes de la secuencia de archivos para ponerlo en el ByteArray bytes. Los 30 primeros bytes conforman la parte de tamaño fijo de la cabecera del primer archivo. // read fixed metadata portion of local file header
zStream.readBytes(bytes, 0, 30);
A continuación el código lee un entero (signature) en los primeros bytes de la cabecera de 30 bytes. La definición del formato ZIP estipula que la firma de cada cabecera de archivo es el valor hexadecimal 0x04034b50; si la firma es distinta, significa que el código se refiere a la parte del archivo .zip que es ajena a los archivos y no hay más archivos que extraer. En ese caso el código sale inmediatamente del bucle while en lugar de esperar hasta alcanzar el final del conjunto de bytes. bytes.position = 0;
signature = bytes.readInt();
// if no longer reading data files, quit
if (signature != 0x04034b50)
{
break;
}
La siguiente parte del bucle lee el byte de la cabecera en la posición de desplazamiento 8 y guarda el valor en la variable compMethod. Este byte contiene un valor que indica el método de compresión que se utilizó para comprimir este archivo. Se admiten varios métodos de compresión, pero en la práctica para casi todos los archivos .zip se utiliza el algoritmo de compresión DEFLATE. Si el archivo actual está comprimido con compresión DEFLATE, compMethod es 8; si el archivo está sin comprimir, compMethod es 0. bytes.position = 8;
compMethod = bytes.readByte(); // store compression method (8 == Deflate)
A los 30 primeros bytes sigue una parte de longitud variable de la cabecera que contiene el nombre del archivo y, tal vez, un campo adicional. El tamaño de esta parte se guarda en la variable offset. El tamaño se calcula sumando la longitud del nombre del archivo y la longitud del campo adicional, leídas en la cabecera en las posiciones de desplazamiento 26 y 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
A continuación el programa lee la parte de longitud variable de la cabecera de archivo donde se indica la cantidad de bytes guardados en la variable offset. // read variable length bytes between fixed-length header and compressed file data
zStream.readBytes(bytes, 30, offset);
El programa lee el nombre del archivo en la parte de longitud variable de la cabecera y lo muestra en el área de texto junto con los tamaños del archivo comprimido (en el archivo zip) y sin comprimir (original). // 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';
En el ejemplo se lee el resto del archivo de la secuencia de archivos para ponerlo en bytes durante la longitud especificada por el tamaño comprimido, sobrescribiendo la cabecera del archivo en los primeros 30 bytes. El tamaño comprimido es exacto aunque el archivo esté sin comprimir porque en ese caso el tamaño comprimido es igual al tamaño del archivo sin comprimir. // read compressed file to offset 0 of bytes; for uncompressed files
// the compressed and uncompressed size is the same
zStream.readBytes(bytes, 0, compSize);
A continuación el código en el ejemplo descomprime el archivo comprimido y llama a la función outfile() para escribirlo en la secuencia de archivos de salida. Pasa a outfile() el nombre del archivo y el conjunto de bytes que contiene los datos del archivo. if (compMethod == 8) // if file is compressed, uncompress
{
bytes.uncompress(CompressionAlgorithm.DEFLATE);
}
outFile(fileName, bytes); // call outFile() to write out the file
Las llaves finales indican el final del bucle while y del método init() y el código de la aplicación de Flex, excepto para el método outFile(). La ejecución regresa al principio del bucle while y sigue procesando los siguientes bytes del archivo .zip, sea extrayendo otro archivo o finalizando el procesamiento del archivo .zip si es que se ha procesado el último archivo. } // end of while loop } // for Flex version, end of init() method and application La función outfile() abre un archivo de salida en modo WRITE (lectura) en el escritorio y le da el nombre suministrado por el parámetro filename. A continuación escribe los datos de los archivos del parámetro data en la secuencia de archivos de salida (outStream) y cierra el archivo. // 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();
}
|
|