在JDK1.0.2中,只有BufferedInputStream 和 BufferedOutputStream两个类提供了有缓冲
的I/O。而这两个类提供的方法的远远不够用的。大多数情况下,我们只能使用没有缓冲的
方法。在JDK1.1中,提供了Reader 和 Writer 两种父类,他们的子类都是有缓冲的,而且
提供了我们所需要的大部分方法。通过缓冲,我们可以得到10至20倍的性能。
可惜的是,某些很有用的类,仍然没有提供缓冲,例如RandomAccessFile。所以在这
种情况下,我们有必要实现自己的缓冲。
看看下面这个类:
public class Braf extends RandomAccessFile {
}
buffer是用作缓冲的byte数组;buf_end、buf_pos和real_pos用于记录buffer的位置
。
byte buffer[];
int buf_end = 0;
int buf_pos = 0;
long real_pos = 0;
新的构造函数增加了参数bufsize,用于定义缓冲的大小。
public Braf(String filename, String mode, int bufsize)
throws IOException{
super(filename,mode);
invalidate();
BUF_SIZE = bufsize;
buffer = new byte[BUF_SIZE];
}
新增的read方法总是从缓冲中读取资料,如果资料不在缓冲中,则调用fillBuffer方
法来更新缓冲区。而原来的的read方法则在fillBuffer中被调用。如果当前的文件指针所
指向的内容不在缓冲中,则invalidate()方法被调用。
public final int read() throws IOException{
if(buf_pos >= buf_end) {
if(fillBuffer() < 0)
return -1;
}
if(buf_end == 0) {
return -1;
} else {
return buffer[buf_pos++];
}
}
private int fillBuffer() throws IOException {
int n = super.read(buffer, 0, BUF_SIZE);
if(n >= 0) {
real_pos +=n;
buf_end = n;
buf_pos = 0;
}
return n;
}
private void invalidate() throws IOException {
buf_end = 0;
buf_pos = 0;
real_pos = super.getFilePointer();
}
为了提高效率,我们也重载了别的read方法。在这个read方法里,如果所需的内容都
在缓冲中,就调用System.arraycopy,把缓冲的内容直接拷贝到用户所提供的地方。
public int read(byte b[], int off, int len) throws IOException {
int leftover = buf_end - buf_pos;
if(len <= leftover) {
System.arraycopy(buffer, buf_pos, b, off, len);
buf_pos += len;
return len;
}
for(int i = 0; i < len; i++) {
int c = this.read();
if(c != -1)
b[off+i] = (byte)c;
else {
return i;
}
}
return len;
}
因为我们使用了缓冲技术,所以getFilePointer和seek方法都必须重写。在大多数情
况下,使用这两个方法都不必进行实际的I/O操作。
public long getFilePointer() throws IOException{
long l = real_pos;
return (l - buf_end + buf_pos) ;
}
public void seek(long pos) throws IOException {
int n = (int)(real_pos - pos);
if(n >= 0 && n <= buf_end) {
buf_pos = buf_end - n;
} else {
super.seek(pos);
invalidate();
}
}
由于在原来的类中readLine被定义为final,我们有必要写一个新的方法来充分发挥缓
冲的优势。这就是getNextLine。如果缓冲区不含所需资料,它会调用方法fillBuffer 来
更新缓冲区。然后读出相应的内容,转换成String,返回。因为使用了缓冲技术,它的性
能比原来的高很多。
/**
* return a next line in String
*/
public final String getNextLine() throws IOException {
String str = null;
if(buf_end-buf_pos <= 0) {
if(fillBuffer() < 0) {
throw new IOException("error in filling buffer!");
}
}
int lineend = -1;
for(int i = buf_pos; i < buf_end; i++) {
if(buffer[i] == '\n') {
lineend = i;
break;
}
}
if(lineend < 0) {
StringBuffer input = new StringBuffer(256);
int c;
while (((c = read()) != -1) && (c != '\n')) {
input.append((char)c);
}
if ((c == -1) && (input.length() == 0)) {
return null;
}
return input.toString();
}
if(lineend > 0 && buffer[lineend-1] == '\r')
str = new String(buffer, 0, buf_pos, lineend - buf_pos -1);
else str = new String(buffer, 0, buf_pos, lineend - buf_pos);
buf_pos = lineend +1;
return str;
}