读取并写入 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 中读取一个字节,直到遇到字符“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 位内存。某些计算机首先将数字中的最高有效字节存储在最低的内存地址,而其他计算机则首先存储最低有效字节。计算机的这一属性(即字节顺序属性)被称为 big endian (最高有效字节位于最前)或 little endian (最低有效字节位于最前)。例如,数字 0x31323334 对于 big endian 和 little endian 字节顺序将分别存储为以下形式,其中 a0 代表 4 个字节的最低内存地址而 a3 代表最高内存地址:

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

利用 ByteArray 类的 endian 属性可以为要处理的多字节数字表示此字节顺序。该属性可接受的值为 "bigEndian" "littleEndian" ,并且 Endian 类定义了常量 BIG_ENDIAN LITTLE_ENDIAN ,从而通过这些字符串设置 endian 属性。

compress() 和 uncompress() 方法

利用 compress() 方法可以根据指定为参数的压缩算法压缩 ByteArray。利用 uncompress() 方法可以根据压缩算法对压缩的 ByteArray 进行解压缩。调用 compress() uncompress() 之后,字节数组的长度将设置为新的长度并且 position 属性将设置为结尾。

CompressionAlgorithm 类 (AIR) 定义了可用来指定压缩算法的常量。ByteArray 类支持 deflate(仅限 AIR)和 zlib 算法。 这种 deflate 压缩算法用于多种压缩格式,如 zlib、gzip 及一些 zip 实现等。在 http://www.ietf.org/rfc/rfc1950.txt 中对 zlib 压缩数据格式进行了说明;在 http://www.ietf.org/rfc/rfc1951.txt 中对 deflate 压缩算法进行了说明。

以下示例使用 deflate 算法压缩名为 bytes 的 ByteArray:

bytes.compress(air.CompressionAlgorithm.DEFLATE);

以下示例使用 deflate 算法对压缩的 ByteArray 进行解压缩:

bytes.uncompress(CompressionAlgorithm.DEFLATE);

读取和写入对象

readObject() writeObject() 方法可从 ByteArray 中读取并向其写入以序列化 Action Message Format (AMF) 格式编码的对象。AMF 是 Adobe 创建并由各种 ActionScript 3.0 类使用的专有消息协议,这些类包括 Netstream、NetConnection、NetStream、LocalConnection 和 SharedObject。

单字节类型标记说明了编码数据遵循的类型。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 进行了改进:通过引用发送对象 traits 和字符串,除对象引用外,还支持 ActionScript 3.0 中引入的新的数据类型。 ByteArray.objectEcoding 属性指定了用于对对象数据进行编码的 AMF 版本。flash.net.ObjectEncoding 类定义了用于指定 AMF 版本的常量: ObjectEncoding.AMF0 ObjectEncoding.AMF3

以下示例调用 writeObject() 将 XML 对象写入 ByteArray 中,随后将该 ByteArray 写入桌面上的 order 文件中。该示例在完成时将在 AIR 窗口中显示消息“Wrote order file to desktop!”

<!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() 方法从 ByteArray 中读取序列化 AMF 格式的对象并将其存储到指定类型的对象中。以下示例将桌面中的 order 文件读入 ByteArray ( inBytes ) 中并调用 readObject() 以将其存储在 orderXML 中,然后将其转换为 XML 对象文档 myXML ,并显示两个项和价格元素的值。该示例还显示了 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>