package com.hundsun.jresplus.common.util.io;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author LeoHu copy by sagahl copy by fish
*
*/
public final class CharArrayWriter extends Writer {
private static final char[] EMPTY_CHAR_ARRAY = new char[0];
/** 每个buffer的长度,缺省为1K */
private int bufferEntrySize = 1024;
private List<char[]> buffers = new ArrayList<char[]>();
/** 当前使用的buffer下标. */
private int currentBufferIndex;
/** 当前buffer */
private char[] currentBuffer;
/** 已写入的数据长度 */
private int count;
/** 每次写的统计 ,统计10次吧 */
private Turn turn = new Turn(10);
public CharArrayWriter() {
needNewBuffer();
}
public CharArrayWriter(int bufferEntrySize) {
this.bufferEntrySize = bufferEntrySize;
}
public int getBufferEntrySize() {
return this.bufferEntrySize;
}
private char[] getBuffer(int index) {
return buffers.get(index);
}
private int getCurrentBufferPos() {
if (count == 0) {
return 0;
}
int pos = count % bufferEntrySize;
if (pos == 0) {
// 一个buffer用光了
needNewBuffer();
return 0;
}
return pos;
}
private void needNewBuffer() {
if (currentBufferIndex < buffers.size() - 1) {
// 还没有未使用的buffer,继续使用老的buffer
currentBufferIndex++;
currentBuffer = getBuffer(currentBufferIndex);
} else {
// 创建新buffer
char[] createOne = new char[bufferEntrySize];
buffers.add(createOne);
currentBuffer = createOne;
currentBufferIndex++;
}
}
@Override
public void write(char[] cbuf, int off, int len) throws IOException {
if ((off < 0) || (off > cbuf.length) || (len < 0)
|| ((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
int remaining = len;
int inBufferPos = getCurrentBufferPos();
while (remaining > 0) {
int part = Math.min(remaining, bufferEntrySize - inBufferPos);
System.arraycopy(cbuf, off + len - remaining, currentBuffer,
inBufferPos, part);
remaining -= part;
count += part;
if (remaining > 0) {
inBufferPos = getCurrentBufferPos();
}
}
}
@Override
public void write(int b) {
int inBufferPos = getCurrentBufferPos();
currentBuffer[inBufferPos] = (char) b;
count++;
}
public int size() {
return count;
}
public void reset() {
int leftBufferCount = turn.addCountGetAvg();
count = 0;
currentBufferIndex = 0;
currentBuffer = getBuffer(0);
curtailBuffer(leftBufferCount);
}
private void curtailBuffer(int n) {
if (n < 1) {
return;
}
if (this.buffers.size() <= n) {
return;
}
for (int i = this.buffers.size() - 1; i >= n; i--) {
this.buffers.remove(i);
}
}
public void writeTo(Writer out) throws IOException {
int remaining = count;
for (int i = 0; i < buffers.size(); i++) {
char[] buf = getBuffer(i);
int c = Math.min(buf.length, remaining);
out.write(buf, 0, c);
remaining -= c;
if (remaining == 0) {
break;
}
}
}
public char[] toCharArray() {
int remaining = count;
if (remaining == 0) {
return EMPTY_CHAR_ARRAY;
}
char newbuf[] = new char[remaining];
int pos = 0;
for (int i = 0; i < buffers.size(); i++) {
char[] buf = getBuffer(i);
int c = Math.min(buf.length, remaining);
System.arraycopy(buf, 0, newbuf, pos, c);
pos += c;
remaining -= c;
if (remaining == 0) {
break;
}
}
return newbuf;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(this.count);
int remaining = this.count;
for (int i = 0; i < buffers.size(); i++) {
char[] buf = getBuffer(i);
int c = Math.min(buf.length, remaining);
sb.append(buf, 0, c);
remaining -= c;
if (remaining == 0) {
break;
}
}
return sb.toString();
}
@Override
public void flush() throws IOException {
// nop
}
@Override
public void close() throws IOException {
// nop
}
/**
* 循环队列
*
*/
private final class Turn {
private Fragment currentFg;
/**
* 创建一个长度为size的循环队列
*/
private Turn(int size) {
Fragment head = new Fragment();
currentFg = head;
for (int i = 0; i < size - 1; i++) {
currentFg.next = new Fragment();
currentFg = currentFg.next;
}
currentFg.next = head;
}
/**
* 增加一个数据并且统计平均值
*/
private int addCountGetAvg() {
if (count != 0) {
currentFg.writeCount = count;
currentFg = currentFg.next;
}
long total = 0L;
int usedFragment = 0;
Fragment f = currentFg.next;
while (f != currentFg) {
total += f.writeCount;
if (f.writeCount != 0) {
usedFragment++;
}
f = f.next;
}
if (usedFragment == 0 || total == 0) {
return count;
}
return (int) (total / usedFragment / bufferEntrySize) + 1;
}
}
private static final class Fragment {
private int writeCount = 0;
private Fragment next;
}
}