Bytearrays lezen en schrijven

Flash Player 9 of hoger, Adobe AIR 1.0 of hoger

De klasse ByteArray is een onderdeel van het pakket flash.utils. Als u een ByteArray-object wilt maken in ActionScript 3.0, importeert u de klasse ByteArray en roept u de constructor op, zoals weergegeven in het volgende voorbeeld:

import flash.utils.ByteArray; 
var stream:ByteArray = new ByteArray();

ByteArray, methoden

Elke zinvolle gegevensstroom wordt geordend in een indeling waarin u de gewenste informatie kunt zoeken. Een record in een eenvoudig werknemersbestand kan bijvoorbeeld een id-nummer, een naam, een adres, een telefoonnummer enzovoort bevatten. Een MP3-geluidsbestand bevat een ID3-code met de titel, de auteur, het album, de publicatiedatum en het genre van het bestand dat wordt gedownload. Door deze indeling weet u in welke volgorde de gegevens in de gegevensstroom zijn opgenomen. U kunt de bytestroom daardoor op een intelligente manier lezen.

De klasse ByteArray bevat diverse methoden waarmee u een gegevensstroom eenvoudiger kunt lezen of schrijven. Enkele van deze methoden zijn: readBytes() en writeBytes() , readInt() en writeInt() , readFloat() en writeFloat() , readObject() en writeObject() , en readUTFBytes() en writeUTFBytes() . Met deze methoden kunt u gegevens uit een gegevensstroom inlezen in variabelen van bepaalde gegevenstypen en vanuit bepaalde gegevenstypen rechtstreeks naar de binaire gegevensstroom schrijven.

Met de volgende code wordt bijvoorbeeld een eenvoudige array met tekenreeksen en getallen met een drijvende komma gelezen en wordt elk element naar een bytearray geschreven. Door de indeling van de array kan de code de juiste ByteArray-methoden ( writeUTFBytes() en writeFloat() ) oproepen voor het schrijven van de gegevens. Door het herhaalde gegevenspatroon wordt het mogelijk de array in een lus te lezen.

// The following example reads a simple Array (groceries), made up of strings 
// and floating-point numbers, and writes it to a ByteArray. 
 
import flash.utils.ByteArray; 
 
// define the grocery list Array 
var groceries:Array = ["milk", 4.50, "soup", 1.79, "eggs", 3.19, "bread" , 2.35] 
// define the ByteArray 
var bytes:ByteArray = new ByteArray(); 
// for each item in the array 
for (var i:int = 0; i < groceries.length; i++) { 
        bytes.writeUTFBytes(groceries[i++]); //write the string and position to the next item 
        bytes.writeFloat(groceries[i]);    // write the float 
        trace("bytes.position is: " + bytes.position);    //display the position in ByteArray 
} 
trace("bytes length is: " +  bytes.length);    // display the length 

De eigenschap position

In de eigenschap position wordt de huidige positie opgeslagen van de pointer die de index van de bytearray bepaalt tijdens het lezen of schrijven. De initiële waarde van de eigenschap position is 0 (nul), zoals wordt weergegeven in de volgende code:

var bytes:ByteArray = new ByteArray(); 
trace("bytes.position is initially: " + bytes.position);     // 0 

Wanneer u een bytearray leest of er naar schrijft, wordt de eigenschap position bijgewerkt met de methode die u gebruikt, zodat wordt verwezen naar de locatie die volgt op de laatste byte die is gelezen of geschreven. Met de volgende code wordt bijvoorbeeld een tekenreeks naar een bytearray geschreven en verwijst de eigenschap position daarna naar de byte die volgt op de tekenreeks in de bytearray:

var bytes:ByteArray = new ByteArray(); 
trace("bytes.position is initially: " + bytes.position);     // 0 
bytes.writeUTFBytes("Hello World!"); 
trace("bytes.position is now: " + bytes.position);    // 12 

Bij een leesbewerking wordt de eigenschap position verhoogd met het aantal gelezen bytes.

var bytes:ByteArray = new ByteArray(); 
 
trace("bytes.position is initially: " + bytes.position);     // 0 
bytes.writeUTFBytes("Hello World!"); 
trace("bytes.position is now: " + bytes.position);    // 12 
bytes.position = 0; 
trace("The first 6 bytes are: " + (bytes.readUTFBytes(6)));    //Hello  
trace("And the next 6 bytes are: " + (bytes.readUTFBytes(6)));    // World! 

U kunt de eigenschap position instellen op een specifieke locatie in de bytearray om vanaf dat punt te lezen of te schrijven.

De eigenschappen bytesAvailable en length

De eigenschappen length en bytesAvailable geven aan hoe lang een bytearray is en hoeveel bytes er aanwezig zijn vanaf de huidige positie tot het einde. In het volgende voorbeeld ziet u hoe u deze eigenschappen kunt gebruiken. In het voorbeeld wordt een tekenreeks met tekst naar de bytearray geschreven en worden vervolgens alle bytes in de array een voor een gelezen totdat het teken ‘a’ of het einde ( bytesAvailable <= 0 ) wordt aangetroffen.

var bytes:ByteArray = new ByteArray(); 
var text:String = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus etc."; 
 
bytes.writeUTFBytes(text); // write the text to the ByteArray 
trace("The length of the ByteArray is: " + bytes.length);    // 70 
bytes.position = 0; // reset position 
while (bytes.bytesAvailable > 0 && (bytes.readUTFBytes(1) != 'a')) { 
    //read to letter a or end of bytes 
} 
if (bytes.position < bytes.bytesAvailable) { 
    trace("Found the letter a; position is: " + bytes.position);     // 23 
    trace("and the number of bytes available is: " + bytes.bytesAvailable);    // 47 
} 

De eigenschap endian

Getallen die uit meerdere bytes bestaan (getallen die in meer dan 1 byte geheugen worden opgeslagen), kunnen op verschillende manieren op computers worden opgeslagen. Een geheel getal kan bijvoorbeeld 4 bytes (32 bits) geheugen in beslag nemen. Op sommige computers wordt de meest significante byte van het getal eerst opgeslagen, op het laagste geheugenadres, en op andere wordt de minst significante byte eerst opgeslagen. Dit kenmerk van een computer (de bytevolgorde) wordt big endian (meest significante byte eerst) of little endian (minst significante byte eerst) genoemd. Het getal 0x31323334 wordt bijvoorbeeld als volgt opgeslagen bij de bytevolgorde big endian en little endian, waarbij a0 het laagste geheugenadres van de 4 bytes is en a3 het hoogste:

Big Endian

Big Endian

Big Endian

Big Endian

a0

a1

a2

a3

31

32

33

34

Little Endian

Little Endian

Little Endian

Little Endian

a0

a1

a2

a3

34

33

32

31

Met de eigenschap endian van de klasse ByteArray kunt u deze bytevolgorde aangeven voor getallen die uit meerdere bytes bestaan. De geaccepteerde waarden voor deze eigenschap zijn "bigEndian" en "littleEndian" en in de klasse Endian zijn de constanten BIG_ENDIAN en LITTLE_ENDIAN gedefinieerd om deze tekenreeksen in te stellen voor de eigenschap endian .

De methoden compress() en uncompress()

Met de methode compress() kunt u een bytearray comprimeren volgens een compressiealgoritme die u opgeeft als een parameter. Met de methode uncompress() kunt u een bytearray decomprimeren volgens een compressiealgoritme. Nadat u compress() en uncompress() hebt opgeroepen, wordt de lengte van de bytearray ingesteld op de nieuwe lengte en wordt de eigenschap position ingesteld op het einde.

In de klasse CompressionAlgorithm zijn constanten gedefinieerd waarmee u de compressiealgoritme kunt opgeven. De klasse ByteArray biedt ondersteuning voor de volgende algoritmen: Deflate (alleen AIR), ZLIB en LZMA. De ZLIB-gecomprimeerde gegevensindeling wordt beschreven in http://www.ietf.org/rfc/rfc1950.txt . De lzma-algoritme is toegevoegd in Flash Player 11.4 en AIR 3.4 en wordt beschreven in http://www.7-zip.org/7z.html .

De Deflate-compressiealgoritme wordt gebruikt in diverse compressie-indelingen, zoals ZLIB, GZIP en enkele ZIP-implementaties. De Deflate-compressiealgoritme wordt beschreven in http://www.ietf.org/rfc/rfc1951.txt .

In het volgende voorbeeld wordt een bytearray met de naam bytes gecomprimeerd met de Izma-algoritme:

bytes.compress(CompressionAlgorithm.LZMA);

In het volgende voorbeeld wordt een gecomprimeerde bytearray gedecomprimeerd met de Deflate-algoritme:

bytes.uncompress(CompressionAlgorithm.LZMA);

Objecten lezen en schrijven

Met de methoden readObject() en writeObject() leest u een object in een bytearray en schrijft u een object naar een bytearray, gecodeerd in geserialiseerde AMF-indeling (Action Message Format). AMF is een berichtenprotocol dat door Adobe is gemaakt en wordt gebruikt door diverse ActionScript 3.0-klassen, zoals Netstream, NetConnection, NetStream, LocalConnection en Shared Objects.

Een typemarkering van één byte bevat de beschrijving van het type van de gecodeerde gegevens die volgen. AMF gebruikt de volgende 13 gegevenstypen:

value-type = undefined-marker | null-marker | false-marker | true-marker | integer-type |  
    double-type | string-type | xml-doc-type | date-type | array-type | object-type | 
    xml-type | byte-array-type

De gecodeerde gegevens volgen op de typemarkering, tenzij de markering één mogelijke waarde bevat, zoals null of true of false, zodat verder niets wordt gecodeerd.

Er zijn twee versies van AMF: AMF0 en AMF3. AMF 0 ondersteunt het verzenden van complexe objecten via verwijzingen en staat eindpunten toe voor het herstellen van objectrelaties. AMF 3 is verbeterd ten opzichte van AMF 0 doordat naast objectverwijzingen ook objectkenmerken en tekenreeksen kunnen worden verzonden en nieuwe gegevenstypen worden ondersteund die in ActionScript 3.0 zijn geïntroduceerd. De eigenschap ByteArray.objectEcoding geeft aan welke versie van AMF wordt gebruikt om de objectgegevens te coderen. In de klasse flash.net.ObjectEncoding zijn constanten gedefinieerd waarmee de AMF-versie wordt opgegeven: ObjectEncoding.AMF0 en ObjectEncoding.AMF3 .

In het volgende voorbeeld wordt writeObject() opgeroepen om een XML-object te schrijven naar een bytearray die daarna met de Deflate-algoritme wordt gecomprimeerd en in het bestand order op de desktop wordt geschreven. In dit voorbeeld wordt een label gebruikt om het bericht “Wrote order file to desktop!” in het AIR-venster weer te geven nadat de bewerking is voltooid.

import flash.filesystem.*; 
import flash.display.Sprite; 
import flash.display.TextField; 
import flash.utils.ByteArray; 

public class WriteObjectExample extends Sprite 
{ 
    public function WriteObjectExample() 
    { 
        var bytes:ByteArray = new ByteArray(); 
        var myLabel:TextField = new TextField(); 
        myLabel.x = 150; 
        myLabel.y = 150; 
        myLabel.width = 200; 
        addChild(myLabel); 
          
        var myXML:XML =  
            <order> 
                <item id='1'> 
                    <menuName>burger</menuName> 
                    <price>3.95</price> 
                </item> 
                <item id='2'> 
                    <menuName>fries</menuName> 
                    <price>1.45</price> 
                </item> 
            </order>; 
          
        // Write XML object to ByteArray 
        bytes.writeObject(myXML); 
        bytes.position = 0;        //reset position to beginning 
        bytes.compress(CompressionAlgorithm.DEFLATE);    // compress ByteArray 
        writeBytesToFile("order.xml", bytes); 
        myLabel.text = "Wrote order file to desktop!"; 
    } 
     
    private function writeBytesToFile(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(); 
    } 
}

Met de methode readObject() wordt een object in geserialiseerde AMF-indeling ingelezen vanuit een bytearray en opgeslagen in een object van het opgegeven type. In het volgende voorbeeld wordt het bestand order vanaf de desktop ingelezen in een bytearray ( inBytes ). Vervolgens wordt het bestand gedecomprimeerd en wordt readObject() opgeroepen om het op te slaan in het XML-object orderXML . In het voorbeeld wordt elk knooppunt in een lusconstructie for each() toegevoegd aan een tekstgebied voor weergave. In het voorbeeld wordt ook de waarde van de eigenschap objectEncoding weergegeven, evenals een header voor de inhoud van het bestand order .

import flash.filesystem.*; 
import flash.display.Sprite; 
import flash.display.TextField; 
import flash.utils.ByteArray; 
 
public class ReadObjectExample extends Sprite 
{ 
    public function ReadObjectExample() 
    { 
        var inBytes:ByteArray = new ByteArray(); 
        // define text area for displaying XML content 
        var myTxt:TextField = new TextField(); 
        myTxt.width = 550; 
        myTxt.height = 400; 
        addChild(myTxt); 
        //display objectEncoding and file heading 
        myTxt.text = "Object encoding is: " + inBytes.objectEncoding + "\n\n" + "order file: \n\n"; 
        readFileIntoByteArray("order", inBytes); 
         
        inBytes.position = 0; // reset position to beginning 
        inBytes.uncompress(CompressionAlgorithm.DEFLATE); 
        inBytes.position = 0;    //reset position to beginning 
        // read XML Object 
        var orderXML:XML = inBytes.readObject(); 
         
        // for each node in orderXML 
        for each (var child:XML in orderXML) 
        { 
            // append child node to text area 
            myTxt.text += child + "\n"; 
        }  
    } 
     
    // read specified file into byte array 
    private function readFileIntoByteArray(fileName:String, data:ByteArray):void 
    { 
        var inFile:File = File.desktopDirectory; // source folder is desktop 
        inFile = inFile.resolvePath(fileName);  // name of file to read 
        var inStream:FileStream = new FileStream(); 
        inStream.open(inFile, FileMode.READ); 
        inStream.readBytes(data); 
        inStream.close(); 
    } 
}