Чтение и запись объектов ByteArray

Flash Player 9 и более поздних версий, Adobe AIR 1.0 и более поздних версий

Класс ByteArray входит в пакет flash.utils. Чтобы создать объект ByteArray в ActionScript 3.0, импортируйте класс ByteArray и вызовите конструктор, как показано ниже:

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

Методы ByteArray

Любой осмысленный поток данных организован в таком формате, который можно проанализировать, чтобы найти нужную информацию. Например, запись в личной карточке сотрудника компании скорее всего будет содержать идентификационный номер, имя, адрес, номер телефона и т. д. MP3-файл содержит тег ID3, задающий название, исполнителя, альбом, дату выпуска и жанр загружаемого файла. Формат позволяет определять порядок данных в потоке. Таким образом можно читать поток и извлекать нужные данные.

Класс ByteArray содержит несколько методов, упрощающих чтение и запись данных в поток. К ним относятся методы readBytes() и writeBytes() , readInt() и writeInt() , readFloat() и writeFloat() , readObject() и writeObject() , а также readUTFBytes() и writeUTFBytes() . Они позволяют читать данные из потока в переменные отдельных типов данных и записывать из отдельных типов данных непосредственно в двоичный поток.

Например, в коде ниже читается простой строковой массив и числа с плавающей точкой, и каждый элемент записывается в объект ByteArray. Благодаря устройству массива код способен вызвать для записи данных нужные методы ByteArray ( writeUTFBytes() и writeFloat() ). Повторяющаяся структура данных позволяет читать массив с помощью цикла.

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

Свойство position

Свойство position сохраняет текущее положение указателя, определяющего ByteArray во время чтения или записи. Исходное значение свойства position равно 0 (нулю), как показано ниже:

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

При чтении или записи в объект ByteArray используемый метод обновляет свойство position, чтобы указать положение, следующее сразу за последним считанным или записанным байтом. Например, в коде ниже строка записывается в ByteArray, а потом свойство position указывает на байт, следующий сразу за строкой в массиве 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 

Таким же образом, операция чтения увеличивает значение свойства position на количество считанных байтов.

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! 

Обратите внимание, что свойство position может указывать и на конкретное положение в объекте ByteArray, из которого следует выполнять чтение или запись.

Свойства bytesAvailable и length

Свойства length и bytesAvailable сообщают длину ByteArray и количество байтов, оставшихся от текущего положения до конца. В примере ниже показано, как могут использоваться эти свойства. Строка текста записывается в объект ByteArray, а потом ByteArray читается по байтам, пока не будет обнаружен символ «а» или конец массива ( 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 
} 

Свойство endian

Компьютеры отличаются друг от друга способами хранения многобайтовых чисел, т. е. чисел, требующих для хранения более одного байта памяти. Например, целое число может занять 4 байта или 32 бита. Одни компьютеры оставляют низший адрес памяти наиболее значимому байту, а другие — наименее значимому. Этот атрибут компьютера — или порядка данных — может называться обратный порядок байтов (сначала самый значимый байт) или прямой порядок байтов (сначала наименее значимый байт). Например, число 0x31323334 при обратном порядке байтов и прямом порядке байтов сохранялось бы следующим образом, исходя из того, что a0 — низший адрес памяти с 4 байтами, а a3 — высший:

Обратный порядок байтов

Обратный порядок байтов

Обратный порядок байтов

Обратный порядок байтов

a0

a1

a2

a3

31

32

33

34

Прямой порядок байтов

Прямой порядок байтов

Прямой порядок байтов

Прямой порядок байтов

a0

a1

a2

a3

34

33

32

31

Свойство endian класса ByteArray позволяет указать тот или иной порядок для многобайтовых чисел. Значением этого свойства может быть "bigEndian" или "littleEndian" , а класс Endian определяет константы BIG_ENDIAN и LITTLE_ENDIAN для задания свойства endian с помощью этих строк.

Методы compress() и uncompress()

Метод compress() позволяет сжимать объект ByteArray согласно алгоритму сжатия, заданному соответствующим параметром. Метод uncompress() позволяет распаковывать сжатые объекты ByteArray в соответствии с алгоритмом сжатия. После вызова методов compress() и uncompress() длина байтового массива изменяется, а свойство position принимает в качестве значения конец массива.

Класс CompressionAlgorithm определяет константы, которые могут использоваться для указания алгоритмов сжатия. Класс ByteArray поддерживает алгоритмы deflate (только для AIR), zlib и lzma. Формат упакованных данных zlib описан в документе http://www.ietf.org/rfc/rfc1950.txt . Алгоритм lzma был добавлен для версий Flash Player 11.4 и AIR 3.4. Его описание доступно по адресу http://www.7-zip.org/7z.html .

Алгоритм сжатия deflate используется несколькими форматами: zlib, gzip и некоторыми вариантами zip. Алгоритм упаковки данных deflate описан в документе http://www.ietf.org/rfc/rfc1951.txt .

В примере ниже объект ByteArray с именем bytes сжимается с помощью алгоритма lzma:

bytes.compress(CompressionAlgorithm.LZMA);

В примере ниже объект ByteArray распаковывается с помощью алгоритма deflate:

bytes.uncompress(CompressionAlgorithm.LZMA);

Чтение и запись объектов

Методы readObject() и writeObject() считывают и записывают объекты в ByteArray, кодируя их в формат AMF (Action Message Format). AMF — это запатентованный протокол передачи сообщений Adobe. Он используется различными классами языка ActionScript 3.0, включая Netstream, NetConnection, NetStream, LocalConnection и Shared Objects.

Однобайтовый маркер указывает на тип закодированных данных. В AMF используется 13 типов данных.

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

Закодированные данные следуют за маркером типа; исключением являются случаи, когда маркер представляет единственно возможное значение, например «null», «true» или «false», и тогда кодирование не осуществляется.

Существуют две версии AMF: AMF0 и AMF3. AMF 0 поддерживает отправку комплексных объектов с помощью ссылки и позволяет восстанавливать отношения объектов в конечных точках. Формат AMF 3 дополняет AMF 0: он, помимо ссылок на объекты, способен отправлять ссылки на характеристики объекта и строки, а также он поддерживает новые типы данных, представленные в ActionScript 3.0. Свойство ByteArray.objectEcoding указывает на версию AMF, которая использовалась для кодирования данных объекта. Класс flash.net.ObjectEncoding определяет константы для указания версии AMF: ObjectEncoding.AMF0 и ObjectEncoding.AMF3 .

В примере ниже метод writeObject() вызывается для записи XML-объекта в ByteArray, который затем сжимает его с помощью алгоритма Deflate и записывает в файл order на рабочем столе. В примере надпись «Wrote order file to desktop!» («Файл записан на рабочий стол!») отображается в окне 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(); 
    } 
}

Метод readObject() читает объект в сериализованном формате AMF из объекта ByteArray и сохраняет его в объекте заданного типа. В примере ниже файл order читается с рабочего стола в объект ByteArray ( inBytes ), распаковывается, а затем вызывается метод readObject() , сохраняющий его в XML-объекте orderXML . В примере используется конструкция цикла for each() , добавляющая каждый узел в текстовую область. В примере также отображается значение свойства objectEncoding и заголовок содержимого файла 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(); 
    } 
}