Akka的IO层设计可以参考这篇文档,本文简单介绍一下ByteString的设计。
Actor之间是通过消息沟通的,但为了避免同步问题,消息必须是Immutable。因此,Akka无法使用byte[]或ByteBuffer,而是设计了ByteString来表示二进制数据。理解这一点很重要,因为ByteString是不可变的,所以ByteString的很多看似修改状态的方法实际上都是返回一个新的ByteString实例。如果对String或BigInteger等Java自带的不可变类比较了解,那么就很容易理解这一点。
ByteString是一种类似Rope的数据结构,如下图所示:
虽然在内部ByteString使用树形结构存储了n个小byte[],但从外部来看,ByteString仍然像是一个大的byte[]。
ByteString是抽象类,不能直接实例化。可以使用工厂方法来创建ByteString实例,ByteString提供了6个工厂方法,如下所示:
public static ByteString empty() public static ByteString fromArray(byte[] array) public static ByteString fromArray(byte[] array, int offset, int length) public static ByteString fromString(String string) public static ByteString fromString(String string, String charset) public static ByteString fromByteBuffer(ByteBuffer buffer)empty()方法返回一个空的ByteString,其余方法可以根据byte[],String或者ByteBuffer来创建ByteString实例。需要注意的是,为了保证状态不可改变,工厂方法可能会对数据进行拷贝。
下面是比较常用的一些ByteString方法(我用String的类似方法给出解释):
大家都知道,在生成一个长字符串的时候,应该用StringBuilder类(或其线程安全版本StringBuffer)。出于同样的目的,Akka提供了ByteStringBuilder来创建ByteString。下面是ByteStringBuilder的用法示例:
ByteStringBuilder bsb = new ByteStringBuilder(); bsb.append(ByteString.fromString("abc")); bsb.putByte((byte) 1); bsb.putInt(32, ByteOrder.BIG_ENDIAN); bsb.putDouble(3.14, ByteOrder.BIG_ENDIAN); bsb.putBytes(new byte[] {1, 2, 3}); ByteString bs = bsb.result();
为了方便的访问ByteString里的数据,Akka提供了ByteIterator类。可以通过ByteString的iterator()方法获得一份ByteIterator实例,下面是ByteIterator的用法示例:
ByteIterator it = bs.iterator(); it.getByte(); it.getInt(ByteOrder.BIG_ENDIAN); it.getDouble(ByteOrder.BIG_ENDIAN); it.getBytes(new byte[10]);
调用ByteStringBuilder的asOutputStream()方法,可以把ByteStringBuilder当成OutputStream来使用。调用ByteIterator的asInputStream()方法,可以把ByteIterator当做InputStream来使用。
ByteString从Immutable的角度来讲,和String很相似(我猜这也是为什么起名为ByteString的原因)。使用ByteString的时候,应该牢记这点。
原文地址:http://blog.csdn.net/zxhoo/article/details/40151377