Ler e escrever um ByteArray

Flash Player 9 e posterior, Adobe AIR 1.0 e posterior

A classe ByteArray é parte do pacote flash.utils. Para criar um objeto ByteArray no ActionScript 3.0, importe a classe ByteArray e invoque o construtor, conforme exibido no seguinte exemplo:

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

Métodos ByteArray

Qualquer fluxo de dados significativo é organizado em um formato que você pode analisar para encontrar as informações desejadas. Um registro em um simples arquivo de um funcionário, por exemplo, provavelmente incluiria um número de ID, um nome, um endereço, um número de telefone e assim por diante. Um arquivo de áudio MP3 contém uma marca ID3 que identifica o título, autor, álbum, data de publicação e gênero do arquivo que está sendo obtido por download. O formato permite que você saiba a ordem na qual esperar os dados no fluxo de dados. Ele permite que você leia o fluxo de bytes de modo inteligente.

A classe ByteArray inclui vários métodos que facilitam ler de e escrever para um fluxo de dados. Alguns desses métodos incluem readBytes() e writeBytes() , readInt() e writeInt() , readFloat() e writeFloat() , readObject() e writeObject() e readUTFBytes() e writeUTFBytes() . Esses métodos permitem que você leia dados do fluxo de dados em variáveis de tipos de dados específicos e escreva de tipos de dados específicos diretamente para o fluxo de dados binário.

Por exemplo, o código a seguir lê uma matriz simples de sequências de caracteres e números de ponto flutuante e escreve cada elemento em um ByteArray. A organização da matriz permite que o código chame os métodos ByteArray apropriados ( writeUTFBytes() e writeFloat() ) para escrever os dados. O padrão de dados repetitivo possibilita ler a matriz com um loop.

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

A propriedade position

A propriedade position armazena a posição atual do ponteiro que indexa ByteArray durante a leitura ou escrita. O valor inicial da propriedade position é 0 (zero), como exibido no seguinte código:

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

Quando você lê de ou escreve em um ByteArray, o método usado atualiza a propriedade position para apontar para o local imediatamente seguindo o último byte lido ou escrito. Por exemplo, o código a seguir escreve uma sequência de caracteres em um ByteArray e, posteriormente, a propriedade position aponta para o byte imediatamente seguindo a sequência de caracteres no 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 

Da mesma forma, uma operação de leitura incrementa a propriedade position pelo número de bytes lidos.

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! 

Observe que você pode definir a propriedade position para um local específico no ByteArray para ler ou escrever naquele deslocamento.

As propriedades bytesAvailable e length

As propriedades length e bytesAvailable dizem a você quanto tempo um ByteArray possui e quantos bytes permanecem nele da posição atual até o fim. O exemplo a seguir ilustra como você pode usar essas propriedades. O exemplo escreve uma sequência de caracteres de texto para o ByteArray e, em seguida, lê um byte de cada vez do ByteArray até que ele encontre o caractere “a” ou o final ( 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 
} 

A propriedade endian

Os computadores podem diferir em como armazenam números de vários bytes, isto é, números que exigem mais de um 1 byte de memória para armazená-los. Um inteiro, por exemplo, pode levar 4 bytes, ou 32 bits, de memória. Alguns computadores armazenam o byte mais significativo do número primeiro, no endereço de memória mais baixo e outros armazenam o byte menos significativo primeiro. Esse atributo de um computador, ou de uma ordem de bytes, é conhecido como sendo big endian (byte mais significativo primeiro) ou little endian (byte menos significativo primeiro). Por exemplo, o número 0x31323334 seria armazenado da seguinte forma para ordem de bytes big endian e little endian, onde a0 representa o endereço de memória mais baixo dos 4 bytes e a3 representa o mais alto:

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

A propriedade endian da classe ByteArray permite que você denote essa ordem de bytes para números de vários bytes que você esteja processando. Os valores aceitáveis para essa propriedade são "bigEndian" ou "littleEndian" e a classe Endian define as constantes BIG_ENDIAN e LITTLE_ENDIAN para definir a propriedade endian com essas sequências de caracteres.

Os métodos compress() e uncompress()

O método compress() permite que você compacte um ByteArray de acordo com um algoritmo de compactação especificado como um parâmetro. O método uncompress() permite que você descompacte um ByteArray compactado de acordo com um algoritmo de compactação. Após chamar compress() e uncompress() , o comprimento da matriz de bytes é definida para o novo comprimento e a propriedade position é definida para o fim.

A classe CompressionAlgorithm define constantes que você pode usar para especificar o algoritmo de compactação. A classe ByteArray suporta os algoritmos deflate (somente no AIR), zlib e lzma. O formato dos dados comprimidos zlib está descrito em http://www.ietf.org/rfc/rfc1950.txt_br . O algoritmo lzma foi adicionado ao Flash Player 11.4 e ao AIR 3.4. Ele é descrito em http://www.7-zip.org/7z.html .

O algoritmo de compactação deflate é usado em vários formatos de compactação, tais como zlib, gzip e algumas implementações zip. O algoritmo de compactação deflate está descrito em http://www.ietf.org/rfc/rfc1951.txt_br .

O exemplo a seguir compacta um ByteArray chamado bytes usando o algoritmo lzma:

bytes.compress(CompressionAlgorithm.LZMA);

O exemplo a seguir descompacta um ByteArray compactado usando o algoritmo deflate:

bytes.uncompress(CompressionAlgorithm.LZMA);

Leitura e escrita de objetos

Os métodos readObject() e writeObject() leem um objeto de e escrevem um objeto para um ByteArray, codificado em AMF serializado. AMF é um protocolo de mensagens proprietário criado pela Adobe e usado por várias classes do ActionScript 3.0, incluindo Netstream, NetConnection, NetStream, LocalConnection e Shared Objects.

Um marcador de tipo de um byte descreve o tipo dos dados codificados que segue. O AMF usa os 13 tipos de dados a seguir:

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

Os dados codificados seguem o marcador de tipo, a menos que o marcador represente um único valor possível, como null ou true ou false, em cujo caso nada mais é codificado.

Existem duas versões do AMF: AMF0 e AMF3. O AMF 0 suporta o envio de objetos complexos por referência e permite pontos de extremidade para restaurar as relações entre objetos. O AMF 3 melhora o AMF 0 enviando características de objetos e sequências de caracteres por referência, além de referências de objetos, e suportando novos tipos de dados introduzidos no ActionScript 3.0. A propriedade ByteArray.objectEcoding especifica a versão do AMF usada para codificar os dados do objeto. A classe flash.net.ObjectEncoding define constantes para especificar a versão do AMF: ObjectEncoding.AMF0 e ObjectEncoding.AMF3 .

O exemplo a seguir chama writeObject() para escrever um objeto XML para um ByteArray, que ele, em seguida compacta usando o algoritmo Deflate e escreve para o arquivo order na área de trabalho. O exemplo usa um rótulo para exibir a mensagem “Arquivo de ordem escrito na área de trabalho!” na janela do AIR quando concluído.

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

O método readObject() lê um objeto no AMF serializado de um ByteArray e o armazena em um objeto do tipo especificado. O exemplo a seguir lê o arquivo order da área de trabalho em um ByteArray ( inBytes ), o descompacta e chama readObject() para armazená-lo no objeto XML orderXML . O exemplo usa uma construção de loop for each() para adicionar cada nó a uma área de texto para exibição. O exemplo também exibe o valor da propriedade objectEncoding juntamente com um cabeçalho para o conteúdo do arquivo 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(); 
    } 
}