Lesen und Schreiben von ByteArrays

Flash Player 9 und höher, Adobe AIR 1.0 und höher

Die ByteArray-Klasse ist Teil des Pakets flash.utils. Erstellen Sie ein ByteArray-Objekt in ActionScript 3.0, indem Sie wie im folgenden Beispiel dargestellt die ByteArray-Klasse importieren und den Konstruktur aufrufen:

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

ByteArray-Methoden

Jeder aussagekräftige Datenstrom ist in einem Format angeordnet, das Sie analysieren können, um die gewünschten Informationen zu finden. Ein Datensatz in einer einfachen Arbeitnehmerdatei enthält zum Beispiel in der Regel eine Kennnummer, einen Namen, eine Adresse, eine Telefonnummer und weitere Daten. Eine MP3-Audiodatei enthält einen ID3-Tag, der Titel, Autor, Album, Veröffentlichungsdatum und Genre der herunterzuladenden Datei angibt. Anhand des Formats wissen Sie, in welcher Reihenfolge Sie die Daten im Datenstrom zu erwarten haben. So können Sie den Bytestrom intelligent lesen.

Die ByteArray-Klasse umfasst mehrere Methoden, die das Lesen von und Schreiben in einem Datenstrom erleichtern. Zu diesen Methoden gehören readBytes() und writeBytes() , readInt() und writeInt() , readFloat() und writeFloat() , readObject() und writeObject() und readUTFBytes() und writeUTFBytes() . Mit diesen Methoden können Sie Daten vom Datenstrom in Variablen bestimmter Datentypen lesen und von bestimmten Datentypen direkt in den binären Datenstrom schreiben.

Der folgende Code liest zum Beispiel ein einfaches Array von Strings und Gleitkommazahlen und schreibt jedes Element in ein ByteArray. Der Aufbau des Arrays erlaubt es dem Code, die entsprechende ByteArray-Methode aufzurufen ( writeUTFBytes() und writeFloat() ), um die Daten zu schreiben. Aufgrund des sich wiederholenden Datenmusters kann das Array mit einer Schleife gelesen werden.

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

Die Eigenschaft „position“

Mit der Eigenschaft „position“ wird die aktuelle Position des Zeigers gespeichert, der das ByteArray während des Lese- oder Schreibvorgangs indiziert. Der Anfangswert der Eigenschaft ist wie im folgenden Code dargestellt 0 (Null):

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

Wenn Sie von einem ByteArray lesen oder in es schreiben, aktualisiert die verwendete Methode die Eigenschaft „position“ so, dass sie auf die Stelle direkt hinter dem letzten Byte verweist, das gelesen oder geschrieben wurde. Der folgende Code schreibt zum Beispiel einen String in ein ByteArray und die Eigenschaft „position“ verweist danach auf das Byte direkt nach dem String im 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 

Bei einem Lesevorgang wird die Eigenschaft „position“ ebenfalls um die Anzahl der gelesenen Byte erhöht.

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! 

Beachten Sie, dass Sie die Eigenschaft „position“ auf eine bestimmte Stelle im ByteArray setzen können, um ab dieser Stelle zu lesen oder zu schreiben.

Die Eigenschaften „bytesAvailable“ und „length“

Die Eigenschaften length und bytesAvailable geben an, wie lang ein ByteArray ist und wie viele Byte ab der aktuellen Position bis zum Ende verbleiben. Im folgenden Beispiel wird gezeigt, wie Sie diese Eigenschaften einsetzen können. Im Beispiel wird ein Textstring in das ByteArray geschrieben und das ByteArray dann Byte für Byte gelesen, bis der Buchstabe „a“ oder das Ende erreicht wird ( bytesAvailable <= 0 ).

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 
} 

Die Eigenschaft „endian“

Verschiedene Computer verwenden verschiedene Verfahren für das Speichern aus mehreren Byte bestehender Zahlen, also Zahlen, die mehr als ein Byte Speicherplatz benötigen. Eine Ganzzahl kann beispielsweise 4 Byte, oder 32 Bit, Speicherplatz beanspruchen. Einige Computer speichern das höchstwertigste Byte der Zahl zuerst, an der niedrigsten Speicheraddresse, andere Computer speichern das niedrigwertigste Byte zuerst. Dieses Attribut der Computer, die Byte-Reihenfolge, wird als big endian (höchstwertigstes Byte zuerst) oder little endian (niedrigwertigstes Byte zuerst) bezeichnet. Die Zahl 0x31323334 wird nach den Systemen big endian und little endian wie folgt gespeichert, wobei a0 für die niedrigste Speicheradresse der 4 Byte steht und a3 für die höchste:

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

Mit der Eigenschaft endian der ByteArray-Klasse können Sie diese Byte-Reihenfolge für aus mehreren Byte bestehende Zahlen, die Sie verarbeiten, angeben. Die anerkannten Werte für diese Eigenschaft lauten entweder „bigEndian" oder „littleEndian" und die Endian-Klasse definiert die Konstanten BIG_ENDIAN und LITTLE_ENDIAN für die Einstellung der Eigenschaft endian mit diesen Strings.

Die Methoden „compress()“ und „uncompress()“

Mit der Methode compress() können Sie ein ByteArray entsprechend eines als Parameter angegebenen Komprimierungsalgorithmus komprimieren. Mit der Methode uncompress() dagegen können Sie ein komprimiertes ByteArray entsprechend eines als Parameter angegebenen Komprimierungsalgorithmus dekomprimieren. Nach Aufruf von compress() und uncompress() werden die Länge des Byte-Arrays auf die neue Länge und die Eigenschaft „position“ auf das Ende gesetzt.

Die CompressionAlgorithm-Klasse definiert Konstanten, mit denen Sie den Komprimierungsalgorithmus angeben können. Die ByteArray-Klasse unterstützt die Algorithmen deflate (nur AIR), zlib und lzma. Eine Beschreibung des komprimierten Datenformats zlib finden Sie unter http://www.ietf.org/rfc/rfc1950.txt . Der lzma-Algorithmus wurde für Flash Player 11.4 und AIR 3.4 hinzugefügt. Eine Beschreibung finden Sie unter http://www.7-zip.org/7z.html .

Der Komprimierungsalgorithmus „deflate“ wird in verschiedenen Komprimierungsformaten wie zlib, gzip und einigen zip-Implementationen verwendet. Eine Beschreibung des Komprimierungsalgorithmus deflate finden Sie unter http://www.ietf.org/rfc/rfc1951.txt .

Im folgenden Beispiel wird ein ByteArray mit dem Namen bytes mithilfe des lzma-Algorithmus komprimiert:

bytes.compress(CompressionAlgorithm.LZMA);

Im folgenden Beispiel wird ein komprimiertes ByteArray mit dem Algorithmus „deflate“ dekomprimiert:

bytes.uncompress(CompressionAlgorithm.LZMA);

Lesen und Schreiben von Objekten

Die Methoden readObject() und writeObject() lesen ein Objekt aus und schreiben es im serialisierten Action Message Format (AMF) in ein ByteArray. AMF ist ein herstellerspezifisches Meldungsprotokoll von Adobe, das in verschiedenen ActionScript 3.0-Klassen, einschließlich Netstream, NetConnection, NetStream, LocalConnection und Shared Objects, eingesetzt wird.

Eine aus einem Byte bestehende Markierung gibt den Typ der kodierten Daten an, die folgen. AMF verwendet die folgenden 13 Datentypen:

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

Die kodierten Daten folgen der Typmarkierung, es sei denn, die Markierung steht für einen einzigen möglichen Wert, wie null, true oder false. In diesem Fall sind sonst keine Daten kodiert.

Es stehen zwei AMF-Versionen zur Verfügung: AMF 0 und AMF 3. AMF 0 unterstützt die Sendung komplexer Objekte durch Referenzen und lässt die Wiederherstellung von Objektbeziehungen durch Endpunkte zu. AMF 3 stellt gegenüber AMF 0 eine Verbesserung dar, da zusätzlich zu den Objektverweisen Objektmerkmale und Strings durch Referenzen gesendet werden können und in ActionScript 3.0 eingeführte neue Datentypen unterstützt werden. Die Eigenschaft ByteArray.objectEcoding gibt die AMF-Version an, die zur Kodierung der Objektdaten verwendet wird. Die Klasse flash.net.ObjectEncoding legt die Konstanten für die Angabe der AMF-Version fest: ObjectEncoding.AMF0 und ObjectEncoding.AMF3 .

Im folgenden Beispiel wird writeObject() aufgerufen, um ein XML-Objekt in ein ByteArray zu schreiben. Dieses wird dann mit dem deflate-Algorithmus komprimiert und in die Datei order auf dem Desktop geschrieben. Nach Abschluss des Vorgangs wird im AIR-Fenster die Meldung „Wrote order file to desktop!“ eingeblendet.

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

Die Methode readObject() liest ein Objekt im serialisierten AMF aus dem ByteArray und speichert es in einem Objekt des angegebenen Typs. Im folgenden Beispiel wird die Datei order aus dem Desktop in ein ByteArray ( inBytes ) gelesen, dekomprimiert und es wird readObject() aufgerufen, um die Daten im XML-Objekt orderXML zu speichern. Es wird das Schleifenkonstrukt for each() verwendet, um jeden Knoten für die Anzeige zu einem Textbereich hinzuzufügen. Das Beispiel zeigt auch den Wert der Eigenschaft objectEncoding sowie einen Header für die Inhalte der Datei order an.

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