ByteArray örneği: Bir .zip dosyasını okuma

Adobe AIR 1.0 ve üstü

Bu örnek, farklı türlerde birçok dosya içeren basit bir .zip dosyasının nasıl okunacağını gösterir. Bu işlemi her dosyanın meta verilerinden ilgili verileri ayıklayarak, her dosyayı bir ByteArray öğesine genişleterek ve dosyayı masaüstüne yazarak yapar.

Bir .zip dosyasının genel yapısı PKWARE Inc.in belirtimine dayalıdır, bu belirtim http://www.pkware.com/documents/casestudies/APPNOTE.TXT adresinde bulunmaktadır. İlki, .zip arşivindeki ilk dosyanın dosya üstbilgisi ve dosya verileridir, ardından her ek dosyanın dosya üstbilgisi ve dosya veri çifti gelir. (Dosya üstbilgisinin yapısı daha ileride anlatılmaktadır.) İkincisi, .zip dosyası isteğe bağlı olarak bir veri tanımlayıcı kaydı içerir (genellikle çıktı zip dosyası diske kaydedilmek yerine bellekte oluşturulduğunda). Üçüncü olarak, birçok ilave isteğe bağlı öğe bulunmaktadır: arşiv şifre çözme üstbilgisi, arşiv ek veri kaydı, merkezi dizin yapısı, Zip64 merkezi dizin kaydının sonu, Zip64 merkezi dizin bulucunun sonu ve merkezi dizin kaydının sonu.

Bu örnekteki kod yalnızca klasör içermeyen zip dosyalarının ayrıştırılması için yazılmıştır ve veri tanımlayıcı kayıtları beklemez. Son veri dosyasını izleyen tüm bilgileri yok sayar.

Her dosya için dosya üstbilgi biçimi şöyledir:

dosya üstbilgisi imzası

4 bayt

gerekli sürüm

2 bayt

genel amaçlı bit bayrağı

2 bayt

sıkıştırma yöntemi

2 bayt (8=DEFLATE; 0=SIKIŞTIRILMAMIŞ)

dosyanın son değiştirilme zamanı

2 bayt

dosyanın son değiştirilme tarihi

2 bayt

crc-32

4 bayt

sıkıştırılmış boyut

4 bayt

sıkıştırılmamış boyut

4 bayt

dosya adı uzunluğu

2 bayt

ek alan uzunluğu

2 bayt

dosya adı

değişken

ek alan

değişken

Dosya üstbilgisinin ardından gerçek dosya verileri gelir, bu veriler sıkıştırma yöntemi bayrağına bağlı olarak sıkıştırılmış veya sıkıştırılmamış olabilir. Dosya verileri sıkıştırılmamışsa bayrak 0'dır (sıfır), DEFLATE algoritması kullanılarak sıkıştırılmışsa 8'dir veya diğer sıkıştırma algoritmaları kullanılmışsa başka bir değerdir.

Bu örneğin kullanıcı arabirimi bir etiket ve metin alanından oluşur (taFiles). Uygulama aşağıdaki bilgileri .zip dosyasında karşılaştığı her dosyanın metin alanına yazar: dosya adı, sıkıştırılmış boyut ve sıkıştırılmamış boyut. Aşağıdaki MXML belgesi uygulamanın Flex versiyonuna ait kullanıcı arabirimini açıklıyor:

<?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>

Programın başlangıcı aşağıdaki görevleri gerçekleştirir:

  • Gerekli sınıfları içeri aktarır

    import flash.filesystem.*; 
    import flash.utils.ByteArray; 
    import flash.events.Event;
  • Kullanıcı arabirimini tanımlar Flash için

    import fl.controls.*; 
     
    //requires TextArea and Label components in the Library 
    var taFiles = new TextArea(); 
    var output = new Label(); 
    taFiles.setSize(320, 150); 
    taFiles.move(10, 30); 
    output.move(10, 10); 
    output.width = 150; 
    output.text = "Contents of HelloAir.zip"; 
    addChild(taFiles); 
    addChild(output);
  • bytes ByteArray öğesini tanımlar

    var bytes:ByteArray = new ByteArray(); 
  • Dosya üstbilgisinden meta verileri saklamak için değişkenleri tanımlar

    // variables for reading fixed portion of file header 
    var fileName:String = new String(); 
    var flNameLength:uint; 
    var xfldLength:uint; 
    var offset:uint; 
    var compSize:uint; 
    var uncompSize:uint; 
    var compMethod:int; 
    var signature:int; 
  • .zip dosyasını temsil etmek için File (zfile) ve FileStream (zStream) nesnelerini tanımlar ve dosyaların ayıklandığı .zip dosyasının konumunu belirtir—masaüstü dizininde “HelloAIR.zip” adlı bir dosya.

    // File variables for accessing .zip file 
    var zfile:File = File.desktopDirectory.resolvePath("HelloAIR.zip"); 
    var zStream:FileStream = new FileStream();

Flex'te, program kodu init() yöntemiyle başlar ve buna kök mx:WindowedApplication için creationComplete işleyicisi etiketi adı verilir.

// for Flex 
private function init():void 
{

Program .zip dosyasını OKUMA modunda açarak başlar.

    zStream.open(zfile, FileMode.READ); 

Ardından, sayısal alanların bayt sıralamasında en düşük değerli baytın önce geldiğini göstermek için bytes öğesinin endian özelliğini LITTLE_ENDIAN olarak ayarlar.

    bytes.endian = Endian.LITTLE_ENDIAN; 

Sonra while() ifadesi, dosya akışındaki geçerli konum dosya boyutundan büyük veya dosya boyutuna eşit olana kadar devam eden bir döngü başlatır.

    while (zStream.position < zfile.size) 
    {

Döngüdeki ilk ifade dosya akışının ilk 30 baytını ByteArray bytes öğesine okur. İlk 30 bayt, ilk dosya üstbilgisinin sabit boyutlu parçasını oluşturur.

        // read fixed metadata portion of local file header 
        zStream.readBytes(bytes, 0, 30);

Sonra kod, 30 baytlık üstbilginin ilk baytlarından bir tam sayı (signature) okur. ZIP biçimi tanımı, her dosya üstbilgi imzasının onaltılık değer 0x04034b50 olduğunu belirtir; imza farklıysa bu, kodun, .zip dosyasının dosya kısmının ötesine taşındığı ve ayıklanacak dosya olmadığı anlamına gelir. Bu durumda kod, bayt sırasının sonunu beklemek yerine hemen while döngüsünden çıkar.

        bytes.position = 0; 
        signature = bytes.readInt(); 
        // if no longer reading data files, quit 
        if (signature != 0x04034b50) 
        { 
            break; 
        }

Kodun sonraki kısmı üstbilgi baytını uzaklık konumu 8'de okur ve değeri compMethod değişkeninde saklar. Bu bayt, bu dosyayı sıkıştırmak için kullanılan sıkıştırma yöntemini gösteren bir değer içerir. Birçok sıkıştırma yöntemi kullanılabilir, ancak uygulamada neredeyse tüm .zip dosyaları DEFLATE sıkıştırma algoritmasını kullanmaktadır. Geçerli dosya DEFLATE sıkıştırmayla sıkıştırıldıysa compMethod 8'dir; dosya sıkıştırılmamışsa, compMethod 0'dır.

        bytes.position = 8; 
        compMethod = bytes.readByte();  // store compression method (8 == Deflate)

İlk 30 baytın ardından, üstbilginin dosya adını ve büyük olasılıkla ek bir alan içeren üstbilginin değişken uzunluklu kısmı gelir. Değişken offset bu kısmın boyutunu saklar. Boyut, uzaklık 26 ve 28'deki üstbilgilerden okunan dosya adı uzunluğu ve ek alan uzunluğu toplanarak hesaplanır.

        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

Sonra program offset değişkeninde saklanan bayt sayısı için dosya üstbilgisinin değişken uzunluklu kısmını okur.

        // read variable length bytes between fixed-length header and compressed file data 
        zStream.readBytes(bytes, 30, offset);

Program, dosya adını üstbilginin değişken uzunluk kısmından okur ve dosyanın sıkıştırılmış (zip) ve sıkıştırılmamış (orijinal) boyutlarıyla birlikte metin alanında görüntüler.

// 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'; 

Örnek, dosyanın geri kalanını sıkıştırılmış boyut tarafından belirtilen uzunluk için dosya akışından bytes öğesine okur ve ilk 30 bayttaki dosya üstbilgisinin üzerine yazar. Dosya sıkıştırılmış olmasa bile sıkıştırılmış boyut doğrudur, çünkü bu durumda sıkıştırılmış boyut dosyanın sıkıştırılmamış boyutuna eşittir.

    // read compressed file to offset 0 of bytes; for uncompressed files 
    // the compressed and uncompressed size is the same 
    zStream.readBytes(bytes, 0, compSize);

Sonra örnek, sıkıştırılmış dosyayı genişletir ve çıktı dosyası akışına yazmak için outfile() işlevini çağırır. outfile() öğesine dosya verilerini içeren dosya adını ve bayt sırasını iletir.

        if (compMethod == 8) // if file is compressed, uncompress 
        { 
            bytes.uncompress(CompressionAlgorithm.DEFLATE); 
        } 
        outFile(fileName, bytes);   // call outFile() to write out the file

Kapatma ayraçları, outFile() yöntemi haricinde, while döngüsünün, init() yönteminin ve uygulama kodunun sonunu gösterir. Çalıştırma while döngüsünün başlangıcına kadar geriye doğru ilerler ve başka bir dosyayı ayıklayarak veya son dosya işlenmişse .zip dosyasını işlemeyi sonlandırarak .zip dosyasında bulunan sonraki baytları işlemeye devam eder.

    } // end of while loop 
} // for Flex version, end of init() method and application

outfile() işlevi bir çıktı dosyasını, dosyaya filename parametresi tarafından sağlanan ismi vererek masaüstünde YAZMA modunda açar. Ardından data parametresindeki dosya verilerini çıktı dosyası akışına (outStream) yazar ve dosyayı kapatır.

// 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(); 
}