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_ENDIANLITTLE_ENDIAN が定義されています。

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

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

CompressionAlgorithm クラス(AIR)で定義されている定数を使用して、圧縮アルゴリズムを指定できます。ByteArray クラスでは、deflate アルゴリズム(AIR のみ)と zlib アルゴリズムの両方をサポートしています。deflate 圧縮アルゴリズムは、zlib、gzip および一部の zip 実装など、いくつかの圧縮形式で使用されています。zlib で圧縮されたデータの形式については、http://www.ietf.org/rfc/rfc1950.txt を参照してください。deflate 圧縮アルゴリズムについては、http://www.ietf.org/rfc/rfc1951.txt を参照してください。

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

bytes.compress(CompressionAlgorithm.DEFLATE);

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

bytes.uncompress(CompressionAlgorithm.DEFLATE);

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

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.AMF0ObjectEncoding.AMF3 が定義されています。

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

/* The following lines, minus comment characters 
, are for Flex version: 
* <?xml version="1.0" encoding="utf-8"?> 
* <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"  
*    creationComplete="init();"> 
* <mx:Script> 
*     <![CDATA[ 
*/ 
import flash.filesystem.*; 
import flash.utils.ByteArray; 
// import mx.controls.Label for Flex 
import fl.controls.Label // for Flash; Label component must be in Library 
// for Flex: private function init():void { 
    var bytes:ByteArray = new ByteArray(); 
    var myLabel:Label = new Label(); 
    myLabel.move(150, 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 
    outFile("order", bytes); 
    myLabel.text = "Wrote order file to desktop!"; 
// for Flex: }     // end of init()function outFile(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(); 
} 
/* Add the following lines for Flex, minus comment characters: 
*     ]]> 
* </mx:Script>             
* </mx:WindowedApplication> 
*/ 

readObject() メソッドは、直列化された AMF のオブジェクトを ByteArray から読み取り、指定された型のオブジェクトに格納します。次の例では、order ファイルをデスクトップから ByteArray(inBytes)に読み取り、圧縮を解除した後、readObject() を呼び出して XML オブジェクト orderXML に格納しています。この例では、for each() ループ構造を使用して、各ノードを表示用のテキスト領域に追加しています。また、objectEncoding プロパティの値を、order ファイルのコンテンツのヘッダーと共に表示しています。

/* The following lines, minus comment characters, are for Flex version: 
* <?xml version="1.0" encoding="utf-8"?> 
* <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" 
*     creationComplete="init();"> 
* <mx:Script> 
*         <![CDATA[ 
*/ 
import flash.filesystem.*; 
import flash.utils.ByteArray; import fl.controls.TextArea; // in Flash, TextArea component must be in Library 
// for Flex version: import mx.controls; 
// for Flex version: private function init():void {    var inBytes:ByteArray = new ByteArray(); 
    // define text area for displaying XML content 
    var myTxt:TextArea = new TextArea(); 
    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"; 
    readFile("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"; 
    }  
// for Flex version: } // end of init() // read specified file into byte array 
function readFile(fileName:String, data:ByteArray) { 
    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, 0, data.length); 
    inStream.close(); 
} 
/* Add the following lines, minus comment characters, for Flex: 
*         ]]> 
*     </mx:Script> 
*      
* </mx:WindowedApplication> 
*/