这是一个很重要的一个字节数组处理缓冲工具,它封装了字节缓冲器及对字节缓冲区的操作,包括对缓冲区的写入、读取、扩展缓冲区大小等等,另外还提供相应字符编码的转码操作。此工具让缓冲操作变得更加方便,除了缓冲区他还有两个channel——ByteInputChannel和ByteOutputChannel,这两个通道一个用于输入读取数据,一个用于输出数据,并且会自动判断缓冲区是否超出规定的缓冲大小,一旦超出则把缓冲区数据全部输出。
如上图,缓冲区buf负责存放待输出的字节数组,此区域有初始值及最大值,在运行时会根据实际进行扩充,一旦到达最大值则马上输出到指定目标。此外还定义了两个内部接口——ByteInputChannel和ByteOutputChannel,一般可以认为一个用于读取数据一个用于输出数据。另外它还包含Chartset对象,有了它可以方便转码工作。下面用一个简化例子说明字节块的工作机制,受篇幅影响,为使例子简洁这里省去了很多方法和Chartset对象,只展示缓冲的工作机制。
① 字节块ByteChunk的简洁实现,包含数据读取输出接口、内存分配方法allocate、缓冲区添加字节方法append、缓冲区扩容方法makeSpace及刷新缓冲区方法flushBuffer。
public final class ByteChunk {
public static interface ByteInputChannel{
public int realReadBytes(bytecbuf[], int off, int len)
throwsIOException;
}
public static interface ByteOutputChannel{
public void realWriteBytes(bytecbuf[], int off, int len)
throwsIOException;
}
private byte[] buff;
private int start = 0;
private int end;
private int limit = -1;
private ByteInputChannel in = null;
private ByteOutputChannel out = null;
public ByteChunk() {
}
public void allocate(int initial, intlimit) {
if (buff == null || buff.length< initial) {
buff = newbyte[initial];
}
this.limit = limit;
start = 0;
end = 0;
}
public void setByteInputChannel(ByteInputChannelin) {
this.in = in;
}
public voidsetByteOutputChannel(ByteOutputChannel out) {
this.out = out;
}
public void append(byte b) throwsIOException {
makeSpace(1);
if (limit > 0 && end>= limit) {
flushBuffer();
}
buff[end++]= b;
}
public void flushBuffer() throwsIOException {
out.realWriteBytes(buff, start,end - start);
end = start;
}
private void makeSpace(int count) {
byte[] tmp = null;
int newSize= buff.length * 2;
if (limit > 0 &&newSize > limit) {
newSize = limit;
}
tmp = new byte[newSize];
System.arraycopy(buff, start,tmp, 0, end - start);
buff = tmp;
tmp = null;
end = end - start;
start = 0;
}
}
② 输出测试类OutputBuffer,此类使用字节块提供的缓冲机制对d盘的hello.txt文件进行写入操作,为更好说明缓冲区工作原理,把字节块的缓冲区初始大小设为3最大为7,我们要把八个字节码写到hello.txt文件,主要看加粗的三行代码,执行dowrite方法时因为长度为8,已经超过了缓冲区最大值,所以进行了一次真实写入操作,接着让程序睡眠十秒,期间你打开hello.txt文件只能看到7个字节数组,它们为1到7(使用十六进制打开)。十秒过后,由于执行了flush刷新操作才把剩下的一个字节写入文件。
public class OutputBuffer implements ByteChunk.ByteOutputChannel{
private ByteChunk fileBuffer;
FileOutputStream fileOutputStream;
public OutputBuffer() {
fileBuffer = new ByteChunk();
fileBuffer.setByteOutputChannel(this);
fileBuffer.allocate(3, 7);
try {
fileOutputStream = newFileOutputStream("d:\\hello.txt");
} catch (FileNotFoundExceptione) {
e.printStackTrace();
}
}
public void realWriteBytes(byte cbuf[],int off, int len)
throws IOException {
fileOutputStream.write(cbuf,off, len);
}
public void flush() throws IOException {
fileBuffer.flushBuffer();
}
public int dowrite(byte[] bytes) throwsIOException {
for (int i = 0; i <bytes.length; i++)
fileBuffer.append(bytes[i]);
return bytes.length;
}
public static void main(String[] args)throws InterruptedException {
OutputBuffer outputBuffer = newOutputBuffer();
byte[] bytes = { 1, 2, 3, 4, 5,6, 7, 8 };
try {
outputBuffer.dowrite(bytes);
Thread.currentThread().sleep(10*1000);
outputBuffer.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
字节块是一个很有用的工具类,它提供了缓冲工具方便我们对某些流添加缓冲区,类似的工具还有字符块CharChunk,顾名思义它是专门用为字符类型的数据提供缓冲操作。