ByteArray の読み取りと書き込み

Flash Player 9 以降、Adobe AIR 1.0 以降

ByteArray クラスは、flash.utils パッケージの一部です。ActionScript 3.0 で ByteArray オブジェクトを作成するには、次の例に示すように、ByteArray クラスを読み込んでコンストラクターを呼び出します。

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

ByteArray のメソッド

意味のあるデータストリームはすべて、分析して目的の情報を発見できるような形式に編成されています。例えば、単純な従業員ファイルのレコードには通常、ID 番号、氏名、住所、電話番号などが含まれます。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 を一度に 1 バイトずつ読み取り、文字「a」または終端( 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 プロパティ

マルチバイトの数値、つまり格納に必要なメモリが 1 バイトより多い数値の格納方法は、コンピューターによって異なる場合があります。例えば、整数の格納に 4 バイト(32 ビット)のメモリを使用するとします。あるコンピューターでは数値の最上位バイトが最初に(最も小さいメモリアドレスに)格納され、別のコンピューターでは最下位バイトが最初に格納されます。このようなコンピューターの属性、すなわちバイト順序の属性は、 ビッグエンディアン (最上位バイトが最初)または リトルエンディアン (最下位バイトが最初)と呼ばれます。例えば、0x31323334 という数値は、バイト順序がビッグエンディアンかリトルエンディアンかに応じて次のように格納されます。a0 は 4 バイトのうちの最小メモリアドレスを表し、a3 は最大メモリアドレスを表します。

ビッグエンディアン

ビッグエンディアン

ビッグエンディアン

ビッグエンディアン

a0

a1

a2

a3

31

32

33

34

リトルエンディアン

リトルエンディアン

リトルエンディアン

リトルエンディアン

a0

a1

a2

a3

34

33

32

31

ByteArray クラスの endian プロパティを使用すると、マルチバイト数値を処理する際のバイト順序を指定することができます。このプロパティに設定できる値は「 bigEndian 」または「 littleEndian 」で、Endian クラスでは endian プロパティを設定するための定数として BIG_ENDIAN LITTLE_ENDIAN が定義されています。

compress() メソッドと uncompress() メソッド

compress() メソッドを使用すると、パラメーターとして指定する圧縮アルゴリズムに従って、ByteArray を圧縮できます。 uncompress() メソッドを使用すると、圧縮アルゴリズムに従って、圧縮されている ByteArray を圧縮解除できます。 compress() および uncompress() の呼び出し後、バイト配列の長さは新しい長さに設定され、position プロパティは終端に設定されます。

CompressionAlgorithm クラスで定義されている定数を使用して、圧縮アルゴリズムを指定できます。ByteArray クラスでは、deflate(AIR のみ)、zlib および lzma アルゴリズムがサポートされます。zlib 圧縮データ形式については、 http://www.ietf.org/rfc/rfc1950.txt の説明を参照してください。Flash Player 11.4 および AIR 3.4 用に、lzma アルゴリズムが追加されました。詳しくは、 http://www.7-zip.org/7z.html の説明を参照してください。

deflate 圧縮アルゴリズムは、zlib、gzip および一部の zip 実装など、いくつかの圧縮形式で使用されています。deflate 圧縮アルゴリズムについては、 http://www.ietf.org/rfc/rfc1951.txt の説明を参照してください。

次の例では、 bytes という名前の ByteArray を lzma アルゴリズムで圧縮しています。

bytes.compress(CompressionAlgorithm.LZMA);

次の例では、deflate アルゴリズムで圧縮された ByteArray の圧縮を解除しています。

bytes.uncompress(CompressionAlgorithm.LZMA);

オブジェクトの読み取りと書き込み

readObject() メソッドと writeObject() メソッドは、直列化された Action Message Format (AMF)でエンコードされた ByteArray のオブジェクトを読み取ったり、書き込んだりします。AMF はアドビ システムズ社が開発した独自のメッセージプロトコルであり、Netstream、NetConnection、NetStream、LocalConnection、Shared Objects など、様々な ActionScript 3.0 クラスで使用されています。

1 バイト型のマーカーが、その後に続くエンコードされたデータの型を示します。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 という 2 つのバージョンがあります。AMF 0 では複雑なオブジェクトの参照渡しがサポートされ、エンドポイントでオブジェクトの関係を復元することができます。AMF 3 は AMF 0 の改良版であり、オブジェクトの参照に加えてオブジェクトの特性とストリングを渡し、ActionScript 3.0 で導入された新しいデータ型をサポートします。 オブジェクトデータのエンコードに使用する AMF のバージョンは、 ByteArray.objectEcoding プロパティで指定します。flash.net.ObjectEncoding クラスでは、AMF のバージョンを指定するための定数として、 ObjectEncoding.AMF0 ObjectEncoding.AMF3 が定義されています。

次の例では、 writeObject() を呼び出して XML オブジェクトを ByteArray に書き込んだ後、Deflate アルゴリズムで圧縮し、デスクトップの order ファイルに書き込んでいます。この例では、終了時に AIR ウィンドウに「Wrote order file to desktop!」というメッセージを表示するために、ラベルを使用しています。

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