您的位置:首页 > Web前端

Java实现的一个高效的循环数据Buffer

2018-03-26 15:08 381 查看
在做一个项目时,需要用到一个字节数据池,意向中应满足以下特点:
1) 支持快速读写;
2) 不要做频繁的内存分配、释放(否则必然会影响速度);

然后,找啊找,在Java标准库中没有找到符合这两个条件的(当然很可能是有但我没找到)。

想了想,决定自己写一个。基本思路是:
1) 分配一块内存,且不再调整;
2) 以数据指针指向读写位置;
3) 一旦读写到内存尾,那么立即跳回头部继续读写;

完整源代码:
import java.io.DataInput;
import java.io.DataOutput;
import java.io.EOFException;
import java.nio.charset.Charset;
import java.util.Arrays;

/**
* 循环数据Buffer
*/
public class CircleBuffer implements DataInput, DataOutput {
private static Charset UTF8_CHARSET = Charset.forName("UTF-8");

private byte[] mBuffer;
private int mCapacity;
private int mWritePosition;
private int mReadableCount;
private int mReadPosition;

public CircleBuffer(int capacity) {
mBuffer = new byte[capacity];
mCapacity = capacity;
reset();
}

@Override
public boolean readBoolean() throws EOFException {
return readByte() != 0;
}

@Override
public byte readByte() throws EOFException {
if (mReadableCount <= 0) throw new EOFException();
if (mReadPosition >= mCapacity) mReadPosition = 0;
mReadableCount--;
return mBuffer[mReadPosition++];
}

@Override
public char readChar() throws EOFException {
return (char) ((readByte() << 8) | (readByte() & 0xFF));
}

@Override
public double readDouble() throws EOFException {
return Double.longBitsToDouble(readLong());
}

@Override
public float readFloat() throws EOFException {
return Float.intBitsToFloat(readInt());
}

@Override
public void readFully(byte[] dst) throws EOFException {
for (int i = 0; i < dst.length; i++) {
dst[i] = readByte();
}
}

@Override
public void readFully(byte[] dst, int offset, int byteCount) throws EOFException {
for (int i = 0; i < byteCount; i++) {
dst[offset + i] = readByte();
}
}

@Override
public int readInt() throws EOFException {
return (((readByte() & 0xFF) << 24) |
((readByte() & 0xFF) << 16) |
((readByte() & 0xFF) << 8) |
((readByte() & 0xFF)));
}

@Override
public String readLine() throws EOFException {
byte[] buffer = new byte[1024];
int count = 0;
while (true) {
byte b = readByte();
if (b == '\r') continue;
if (b == '\n') break;
if (count >= buffer.length) {
buffer = Arrays.copyOf(buffer, buffer.length * 2);
}
buffer[count++] = b;
}

return new String(buffer, 0, count);
}

@Override
public long readLong() throws EOFException {
4000

return ((((long) readByte() & 0xFF) << 56) |
(((long) readByte() & 0xFF) << 48) |
(((long) readByte() & 0xFF) << 40) |
(((long) readByte() & 0xFF) << 32) |
(((long) readByte() & 0xFF) << 24) |
(((long) readByte() & 0xFF) << 16) |
(((long) readByte() & 0xFF) << 8) |
(((long) readByte() & 0xFF)));
}

@Override
public short readShort() throws EOFException {
return (short) ((readByte() << 8) | (readByte() & 0xFF));
}

@Override
public int readUnsignedByte() throws EOFException {
return readByte() & 0xFF;
}

@Override
public int readUnsignedShort() throws EOFException {
return (readByte() << 8) | (readByte() & 0xFF);
}

@Override
public String readUTF() throws EOFException {
int length = readInt();
byte[] values = new byte[length];
readFully(values);
return new String(values, UTF8_CHARSET);
}

@Override
public int skipBytes(int count) throws EOFException {
for (int i = 0; i < count; i++) {
readByte();
}
return count;
}

@Override
public void write(byte[] buffer) {
for (int i = 0; i < buffer.length; i++) {
writeByte(buffer[i]);
}
}

@Override
public void write(byte[] buffer, int offset, int count) {
for (int i = 0; i < count; i++) {
writeByte(buffer[offset + i]);
}
}

@Override
public void write(int oneByte) {
writeByte(oneByte);
}

@Override
public void writeBoolean(boolean val) {
writeByte(val ? 1 : 0);
}

@Override
public void writeByte(int val) {
if (mWritePosition >= mCapacity) mWritePosition = 0;
mReadableCount++;
mBuffer[mWritePosition++] = (byte) val;
}

@Override
public void writeBytes(String str) {
byte[] bytes = str.getBytes();
write(bytes);
}

@Override
public void writeChar(int val) {
writeByte((val >>> 8) & 0xFF);
writeByte((val >>> 0) & 0xFF);
}

@Override
public void writeChars(String str) {
writeBytes(str);
}

@Override
public void writeDouble(double val) {
writeLong(Double.doubleToLongBits(val));
}

@Override
public void writeFloat(float val) {
writeInt(Float.floatToIntBits(val));
}

@Override
public void writeInt(int val) {
writeByte((val >>> 24) & 0xFF);
writeByte((val >>> 16) & 0xFF);
writeByte((val >>> 8) & 0xFF);
writeByte((val) & 0xFF);
}

@Override
public void writeLong(long val) {
writeByte((int) (val >>> 56) & 0xFF);
writeByte((int) (val >>> 48) & 0xFF);
writeByte((int) (val >>> 40) & 0xFF);
writeByte((int) (val >>> 32) & 0xFF);
writeByte((int) (val >>> 24) & 0xFF);
writeByte((int) (val >>> 16) & 0xFF);
writeByte((int) (val >>> 8) & 0xFF);
writeByte((int) (val) & 0xFF);
}

@Override
public void writeShort(int val) {
writeByte((val >>> 8) & 0xFF);
writeByte((val) & 0xFF);
}

@Override
public void writeUTF(String str) {
byte[] values = str.getBytes(UTF8_CHARSET);
writeInt(values.length);
write(values);
}

public void reset() {
mReadableCount = 0;
mReadPosition = 0;
mWritePosition = 0;
}

public byte[] buffer() {
return mBuffer;
}

public int capacity() {
return mCapacity;
}

public int readable() {
return mReadableCount;
}
}

阅读上面的代码,可知这个工具类CircleBuffer,同时实现了两个标准Java接口DataInput和DataOutput。核心方法有三个:
1) 构造方法,用于管理内存(一次分配然后不用再管);
2) 读数据方法readByte,其中的核心在于:if (mReadPosition >= mCapacity) mReadPosition = 0;
3) 写数据方法writeByte,其中的核心在于:if (mWritePosition >= mCapacity) mWritePosition = 0;
其他的方法基本上都是readByte和writeByte的应用。

使用这个工具类,一边尽管往里写,另一边尽管往外读,不用担心冲突,不用担心内存溢出、资源回收甚至out of memory。

很简单吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐