Exemple ByteArray : lecture d’un fichier .zipAdobe AIR 1.0 et ultérieur Cet exemple indique comment lire un fichier .zip simple contenant plusieurs fichiers de types différents. Pour parvenir à lire un tel fichier, les données pertinentes sont extraites des métadonnées pour chacun des fichiers, lesquels sont décompressés dans des classes ByteArray individuelles et écrits dans le poste de travail. La structure générale d’un fichier .zip repose sur la spécification PKWARE Inc., laquelle est tenue à jour à l’adresse http://www.pkware.com/documents/casestudies/APPNOTE.TXT. Elle commence par l’en-tête et les données du premier fichier de l’archive .zip, suivis de la paire en-tête/données de chaque fichier supplémentaire. (La structure de l’en-tête des fichiers est décrite plus loin dans ce document.) Le fichier .zip comprend éventuellement un enregistrement du descripteur de données (généralement lorsque le fichier zip de sortie a été créé dans la mémoire au lieu d’être enregistré sur un disque). Divers éléments facultatifs viennent ensuite : en-tête de déchiffrement de l’archive, enregistrement des données supplémentaires de l’archive, structure de répertoires centrale, fin Zip64 de l’enregistrement de répertoires central, fin Zip64 du localisateur de répertoires central et fin de l’enregistrement de répertoires. Le code présenté dans cet exemple a été rédigé dans le seul objectif d’analyser des fichiers zip ne contenant pas de dossiers ; il n’attend pas d’enregistrements de descripteurs de données. Il ne tient pas compte des informations suivant les données du dernier fichier. Le format de l’en-tête de fichier de chaque fichier est défini de la manière suivante :
L’en-tête du fichier est suivi des véritables données du fichier, au format compressé ou décompressé, suivant l’indicateur de méthode de compression utilisé. L’indicateur est égal à 0 (zéro) si les données du fichier sont décompressées, à 8 si les données sont compressées à l’aide de l’algorithme DEFLATE ou à une autre valeur lorsque les données utilisent d’autres algorithmes de compression. L’interface utilisateur choisie dans cet exemple se compose d’une étiquette et d’une zone de texte (taFiles). L’application écrit les informations suivantes dans la zone de texte pour chaque fichier détecté dans le fichier .zip : nom du fichier, taille compressée et taille décompressée. Le document MXML suivant définit l’interface utilisateur de la version Flex de l’application : <?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> Le début du programme effectue les tâches suivantes :
Dans Flex, le code du programme commence dans la méthode init(), laquelle est appelée en tant que gestionnaire creationComplete pour la balise mx:WindowedApplication racine. // for Flex private function init():void { Le programme commence par ouvrir le fichier .zip en mode READ (lecture). zStream.open(zfile, FileMode.READ); Il configure ensuite la propriété endian de bytes sur la valeur LITTLE_ENDIAN afin d’indiquer que l’ordre d’octets des champs numériques commence par l’octet le moins important. bytes.endian = Endian.LITTLE_ENDIAN; Une instruction while() commence ensuite une boucle qui s’interrompt uniquement lorsque la position active dans le flux de fichier est supérieure ou égale à la taille du fichier. while (zStream.position < zfile.size) { La première instruction au sein de la boucle lit les 30 premiers octets du flux de fichier dans la classe ByteArray bytes. Les 30 premiers octets constituent la partie à taille fixe de l’en-tête du premier fichier. // read fixed metadata portion of local file header zStream.readBytes(bytes, 0, 30); Le code lit ensuite un nombre entier (signature) à partir des premiers octets de l’en-tête de 30 octets. La définition du format ZIP indique que la signature de chaque en-tête de fichier correspond à la valeur hexadécimale 0x04034b50 ; si la signature est différente, cela signifie que le code a dépassé la section des fichiers contenus dans le fichier .zip et qu’il ne reste plus aucun fichier à extraire. Dans ce cas, le code quitte immédiatement la boucle while au lieu d’attendre la fin du tableau d’octets. bytes.position = 0; signature = bytes.readInt(); // if no longer reading data files, quit if (signature != 0x04034b50) { break; } La partie suivante du code lit l’octet d’en-tête à la position décalée 8 et stocke la valeur dans la variable compMethod. Cet octet contient une valeur indiquant la méthode de compression appliquée à ce fichier. Plusieurs méthodes de compression sont autorisées, mais en pratique, presque tous les fichiers .zip utilisent l’algorithme de compression DEFLATE. Si le fichier actif est compressé à l’aide de la méthode de compression DEFLATE, compMethod est égal à 8 ; si le fichier n’est pas compressé, compMethod est égal à 0. bytes.position = 8; compMethod = bytes.readByte(); // store compression method (8 == Deflate) Les 30 premiers octets sont suivis par une partie d’en-tête à longueur variable contenant le nom du fichier et, éventuellement, un champ supplémentaire. La variable offset stocke la taille de cette partie. La taille est calculée en ajoutant la longueur du nom de fichier à la longueur du champ supplémentaire, lue à partir de l’en-tête aux décalages 26 et 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 Le programme lit ensuite la partie à longueur variable de l’en-tête du fichier pour identifier le nombre d’octets stockés dans la variable offset. // read variable length bytes between fixed-length header and compressed file data zStream.readBytes(bytes, 30, offset); Le programme lit le nom du fichier à partir de la partie variable de l’en-tête et l’affiche dans la zone de texte accompagné des tailles compressée (zippée) et décompressée (initiale) du fichier. // 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’exemple de code lit le reste du fichier à partir du flux de fichier en octets (bytes) selon la longueur indiquée par la taille compressée, écrasant ainsi l’en-tête de fichier dans les 30 premiers octets. La taille compressée est exacte et ce, même si le fichier n’est pas compressé, car elle équivaut alors à la taille décompressée du fichier. // read compressed file to offset 0 of bytes; for uncompressed files // the compressed and uncompressed size is the same zStream.readBytes(bytes, 0, compSize); Dans la suite de l’exemple, le fichier compressé est décompressé et la fonction outfile() est appelée afin de l’écrire dans le flux du fichier de sortie. Le code passe à outfile() le nom du fichier et le tableau d’octets contenant les données du fichier. if (compMethod == 8) // if file is compressed, uncompress { bytes.uncompress(CompressionAlgorithm.DEFLATE); } outFile(fileName, bytes); // call outFile() to write out the file Les accolades de fermeture indiquent la fin de la boucle while, de la méthode init() et du code de l’application Flex, à l’exception de la méthode outFile(). L’exécution revient au début de la boucle while et poursuit le traitement des octets suivants du fichier .zip, soit en extrayant un autre fichier soit en mettant un terme au traitement du fichier .zip si le dernier fichier a été traité. } // end of while loop } // for Flex version, end of init() method and application La fonction outfile() ouvre un fichier de sortie en mode WRITE (écriture) dans le poste de travail en lui donnant le nom fourni par le paramètre filename. Elle écrit ensuite les données du fichier issues du paramètre data dans le flux du fichier de sortie (outStream) et ferme le fichier. // 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(); } |
|