ByteArray の読み取りと書き込み

Flash Player 9 以降、Adobe AIR 1.0 以降

ByteArray クラスは flash.utils パッケージの一部です。コードに AIRAliases.js ファイルが含まれている場合は、エイリアス air.ByteArray を使用して ByteArray クラスを参照することもできます。ByteArray を作成するには、次の例に示すように ByteArray コンストラクターを呼び出します。

var stream = new air.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. 
 
// define the grocery list Array 
var groceries = ["milk", 4.50, "soup", 1.79, "eggs", 3.19, "bread" , 2.35] 
// define the ByteArray 
var bytes = new air.ByteArray(); 
// for each item in the array 
for (i = 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 
        air.trace("bytes.position is: " + bytes.position); //display the position in ByteArray 
} 
air.trace("bytes length is: " +  bytes.length);    // display the length

position プロパティ

position プロパティには、読み取り中または書き込み中の ByteArray のインデックスを示すポインターの現在位置が格納されます。次のコードに示すように、position プロパティの初期値は 0(ゼロ)です。

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

ByteArray の読み書きを行うと、使用したメソッドによって position プロパティが更新され、最後に読み書きしたバイトの直後の位置を指すようになります。例えば次のコードでは、ストリングを ByteArray に書き込んだ後、position プロパティは ByteArray 内のストリングの直後のバイトを指すようになります。

var bytes = new air.ByteArray(); 
air.trace("bytes.position is initially: " + bytes.position);     // 0 
bytes.writeUTFBytes("Hello World!"); 
air.trace("bytes.position is now: " + bytes.position);    // 12

同様に、読み取り操作を行うと、読み取ったバイト数だけ position プロパティがインクリメントされます。

var bytes = new air.ByteArray(); 
 
air.trace("bytes.position is initially: " + bytes.position);     // 0 
bytes.writeUTFBytes("Hello World!"); 
air.trace("bytes.position is now: " + bytes.position);    // 12 
bytes.position = 0; 
air.trace("The first 6 bytes are: " + (bytes.readUTFBytes(6)));    //Hello  
air.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 = new air.ByteArray(); 
var text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus etc."; 
 
bytes.writeUTFBytes(text); // write the text to the ByteArray 
air.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) { 
    air.trace("Found the letter a; position is: " + bytes.position);     // 23 
    air.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 クラス(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(air.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.AMF0 ObjectEncoding.AMF3 が定義されています。

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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<style type="text/css"> 
        #taFiles 
        { 
            border: 1px solid black; 
            font-family: Courier, monospace; 
            white-space: pre; 
            width: 95%; 
            height: 95%; 
            overflow-y: scroll; 
        } 
</style> 
<script type="text/javascript" src="AIRAliases.js" ></script> 
<script type="text/javascript"> 
 
//define ByteArray 
var inBytes = new air.ByteArray(); 
//add objectEncoding value and file heading to output text 
var output = "Object encoding is: " + inBytes.objectEncoding + "\n\n" + "order file: \n\n"; 
 
function init() { 
     
    readFile("order", inBytes); 
    inBytes.position = 0;    //reset position to beginning 
    // read XML from ByteArray 
    var orderXML = inBytes.readObject(); 
    // convert to XML Document object 
    var myXML = (new DOMParser()).parseFromString(orderXML, "text/xml"); 
    document.write(myXML.getElementsByTagName("menuName")[0].childNodes[0].nodeValue + ": ");  
       document.write(myXML.getElementsByTagName("price")[0].childNodes[0].nodeValue + "<br/>");      // burger: 3.95 
       document.write(myXML.getElementsByTagName("menuName")[1].childNodes[0].nodeValue + ": ");  
       document.write(myXML.getElementsByTagName("price")[1].childNodes[0].nodeValue + "<br/>");       // fries: 1.45 
}    // end of init() 
 
// read specified file into byte array 
function readFile(fileName, data) { 
    var inFile = air.File.desktopDirectory; // source folder is desktop 
    inFile = inFile.resolvePath(fileName);  // name of file to read 
    var inStream = new air.FileStream(); 
    inStream.open(inFile, air.FileMode.READ); 
    inStream.readBytes(data, 0, data.length); 
    inStream.close(); 
} 
</script> 
</head> 
 
<body onload = "init();"> 
        <div id="taFiles"></div> 
</body> 
</html>

readObject() メソッドは、直列化された AMF のオブジェクトを ByteArray から読み取り、指定された型のオブジェクトに格納します。次の例では、 order ファイルをデスクトップから ByteArray( inBytes )に読み取り、 readObject() を呼び出して orderXML に格納した後、XML オブジェクトドキュメント myXML に変換して、2 つのアイテムエレメントと価格エレメントの値を表示しています。また、 objectEncoding プロパティの値を、 order ファイルのコンテンツのヘッダーと共に表示しています。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<style type="text/css"> 
        #taFiles 
        { 
            border: 1px solid black; 
            font-family: Courier, monospace; 
            white-space: pre; 
            width: 95%; 
            height: 95%; 
            overflow-y: scroll; 
        } 
    </style> 
<script type="text/javascript" src="AIRAliases.js" ></script> 
<script type="text/javascript"> 
 
//define ByteArray 
var inBytes = new air.ByteArray(); 
//add objectEncoding value and file heading to output text 
var output = "Object encoding is: " + inBytes.objectEncoding + "<br/><br/>" + "order file items:" + "<br/><br/>"; 
 
function init() { 
     
    readFile("order", inBytes); 
    inBytes.position = 0;    //reset position to beginning 
    // read XML from ByteArray 
    var orderXML = inBytes.readObject(); 
    // convert to XML Document object 
    var myXML = (new DOMParser()).parseFromString(orderXML, "text/xml"); 
    document.write(output); 
    document.write(myXML.getElementsByTagName("menuName")[0].childNodes[0].nodeValue + ": ");  
       document.write(myXML.getElementsByTagName("price")[0].childNodes[0].nodeValue + "<br/>");      // burger: 3.95 
       document.write(myXML.getElementsByTagName("menuName")[1].childNodes[0].nodeValue + ": ");  
       document.write(myXML.getElementsByTagName("price")[1].childNodes[0].nodeValue + "<br/>");       // fries: 1.45 
}    // end of init() 
 
 
// read specified file into byte array 
function readFile(fileName, data) { 
    var inFile = air.File.desktopDirectory; // source folder is desktop 
    inFile = inFile.resolvePath(fileName);  // name of file to read 
    var inStream = new air.FileStream(); 
    inStream.open(inFile, air.FileMode.READ); 
    inStream.readBytes(data, 0, data.length); 
    inStream.close(); 
} 
</script> 
</head> 
 
<body onload = "init();"> 
        <div id="taFiles"></div> 
</body> 
</html>