Lettura e scrittura di un ByteArray
Flash Player 9 e versioni successive, Adobe AIR 1.0 e versioni successive
La classe ByteArray fa parte del pacchetto flash.utils. Per creare un oggetto ByteArray in ActionScript 3.0, importate la classe ByteArray e chiamate il constructor, come illustrato nel seguente esempio:
import flash.utils.ByteArray;
var stream:ByteArray = new ByteArray();
Metodi ByteArray
Un flusso di dati significativo è organizzato in un formato che è possibile analizzare per trovare le informazioni desiderate. Un record in un file di dipendenti semplice, ad esempio, include probabilmente un numero di identificazione, un nome, un indirizzo, un numero di telefono e così via, mentre un file audio MP3 contiene un tag ID3 che identifica il titolo, l'autore, l'album, la data di pubblicazione e il genere del file che si sta scaricando. Il formato consente di conoscere l'ordine in cui prevedere i dati nel flusso di dati e di leggere tale flusso in modo intelligente.
La classe ByteArray include diversi metodi che semplificano la lettura e la scrittura in un flusso di dati. Alcuni di questi metodi includono
readBytes()
e
writeBytes()
,
readInt()
e
writeInt()
,
readFloat()
e
writeFloat()
,
readObject()
e
writeObject()
, and
readUTFBytes()
e
writeUTFBytes()
. Tali metodi consentono di leggere i dati dal flusso di dati in variabili di tipi di dati specifici, nonché di scrivere da tipi di dati specifici direttamente nel flusso di dati binario.
Ad esempio, il codice riportato di seguito legge un semplice array di stringhe e di numeri a virgola mobile e scrive ciascun elemento in un ByteArray. L'organizzazione dell'array consente al codice di chiamare i metodi ByteArray appropriati (
writeUTFBytes()
e
writeFloat()
) per la scrittura dei dati. Il modello di dati ripetitivo rende possibile la lettura ciclica dell'array.
// 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
La proprietà position
La proprietà position consente di archiviare la posizione corrente del puntatore che indicizza il ByteArray durante lettura o scrittura. Il valore iniziale della proprietà position property è 0 (zero), come illustrato nel codice seguente:
var bytes:ByteArray = new ByteArray();
trace("bytes.position is initially: " + bytes.position); // 0
Quando si legge o si scrive in un ByteArray, il metodo utilizzato aggiorna la proprietà position in modo che punti al percorso immediatamente successivo all'ultimo byte letto o scritto. Ad esempio, il codice seguente scrive una stringa in un ByteArray e successivamente la proprietà position punta al byte che segue immediatamente la stringa in 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
Analogamente, un'operazione di lettura incrementa la proprietà position in base al numero di byte letti.
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!
Si noti che è possibile impostare la proprietà position su una posizione specifica di ByteArray in modo che la lettura o la scrittura venga effettuata a quell'offset.
Le proprietà bytesAvailable e length
Le proprietà
length
e
bytesAvailable
indicano quanto è lungo un ByteArray e quanti byte restano dalla posizione corrente fino alla fine. Nell'esempio seguente viene illustrato come è possibile utilizzare queste proprietà. Nell'esempio viene scritta una Stringa di testo nel ByteArray e quindi il ByteArray viene letto un byte alla volta fino a che incontra il carattere “a” oppure la fine (
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
}
La proprietà endian
I computer possono presentare differenze nel modo in cui memorizzano numeri multibyte, vale a dire numeri che richiedono più di 1 byte di memoria per la memorizzazione. Un numero intero, ad esempio, può richiedere 4 byte o 32 bit di memoria. Alcuni computer memorizzano innanzitutto il byte più significativo del numero nell'indirizzo di memoria più basso, mentre altri memorizzano prima quello meno significativo. Questo attributo di un computer, o dell'ordinamento di byte, viene definito come
big endian
(prima il byte più significativo) o
little endian
(prima il byte meno significativo). Ad esempio, il numero 0x31323334 verrebbe archiviato come segue per l'ordinamento di byte big endian e little endian, laddove a0 indica l'indirizzo di memoria più basso dei 4 byte e a3 rappresenta quello più 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
|
La proprietà
endian
della classe ByteArray consente di denotare l'ordine dei byte per i numeri multibyte che si sta elaborando. I valori accettabili per questa proprietà sono
"bigEndian"
o
"littleEndian"
, e la classe Endian definisce le costanti
BIG_ENDIAN
e
LITTLE_ENDIAN
per impostare la proprietà
endian
con tali stringhe.
I metodi compress() e uncompress()
Il metodo
compress()
consente di comprimere un ByteArray in conformità a un algoritmo di compressione specificato come parametro dall'utente. Il metodo
uncompress()
consente di decomprimere un ByteArray compresso in conformità a un algoritmo di compressione. Dopo aver chiamato i metodi
compress()
e
uncompress()
, la lunghezza dell'array di byte è impostata sulla nuova lunghezza, mentre la proprietà position è impostata sulla fine.
La classe CompressionAlgorithm definisce le costanti che è possibile utilizzare per specificare l'algoritmo di compressione. La classe ByteArray supporta gli algoritmi deflate (solo AIR), zlib e lzma. È possibile leggere la descrizione del formato di dati compresso zlib alle pagine
e http://www.ietf.org/rfc/rfc1950.txt
. L'algoritmo di compressione lzma è stato aggiunto per Flash Player 11.4 e AIR 3.4 ed è descritto qui:
http://www.7-zip.org/7z.html
.
L'algoritmo di compressione deflate è utilizzato in diversi formati di compressione, ad esempio zlib, gzip e alcune implementazioni zip. L'algoritmo di compressione deflate è descritto all'indirizzo
http://www.ietf.org/rfc/rfc1951.txt
.
Nell'esempio seguente viene compresso un ByteArray denominato
bytes
mediante l'algoritmo lzma:
bytes.compress(CompressionAlgorithm.LZMA);
Nell'esempio seguente un ByteArray compresso viene decompresso mediante l'algoritmo deflate:
bytes.uncompress(CompressionAlgorithm.LZMA);
Lettura e scrittura di oggetti
I metodi
readObject()
e
writeObject()
leggono un oggetto e scrivono un oggetto in un ByteArray, codificato in linguaggio AMF (Action Message Format) serializzato. AMF è un protocollo di messaggistica proprietario creato da Adobe e utilizzato da varie classi ActionScript 3.0, incluse Netstream, NetConnection, NetStream, LocalConnection e Shared Objects.
Un indicatore di tipo a un solo byte descrive il tipo di dati codificati che seguono. AMF utilizza i seguenti 13 tipi di dati:
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
I dati codificati seguono l'indicatore di tipi a meno che tale indicatore non rappresenti un singolo valore possibile, ad esempio null, true o false, nel qual caso null'altro viene codificato.
Sono presenti due versioni di AMF: AMF0 e AMF3. AMF 0 supporta l'invio di oggetti complessi in base a riferimento e consente agli endpoint di ripristinare le relazioni tra gli oggetti. AMF 3 migliora AMF 0 mediante l'invio di oggetti trait e stringhe in base a riferimento, oltre ai riferimenti agli oggetti, e mediante il supporto di nuovi tipi di dati introdotti in ActionScript 3.0. La proprietà
ByteArray.objectEcoding
consente di specificare la versione di AMF utilizzata per la codifica dei dati oggetto. La classe flash.net.ObjectEncoding definisce le costanti per la specifica della versione AMF:
ObjectEncoding.AMF0
e
ObjectEncoding.AMF3
.
Nell'esempio seguente viene chiamato
writeObject()
per la scrittura di un oggetto XML in un ByteArray, che viene quindi compresso mediante l'algoritmo Deflate e scritto nel file
order
sul desktop. Nell'esempio viene utilizzata un'etichetta per visualizzare il messaggio “Wrote order file to desktop!” (File di ordinamento scritto sul desktop), al termine nella finestra AIR.
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();
}
}
Il metodo
readObject()
regge un oggetto in formato AMF serializzato da un ByteArray e lo archivia in un oggetto del tipo specificato. Nell'esempio seguente il file
order
sul desktop viene letto in un ByteArray (
inBytes
) e decompresso. Viene quindi effettuata la chiamata a
readObject()
per archiviarlo nell'oggetto XML
orderXML
. Nell'esempio viene utilizzato un costrutto di ciclo
for each()
per aggiungere ciascun nodo a un'area di testo per la visualizzazione. Inoltre, viene visualizzato il valore della proprietà
objectEncoding
insieme a un'intestazione per il contenuto del file
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();
}
}
|
|
|
|
|