RandomAccessFile利用file pointer(文件指针),可以从给定的位置开始读取所需的数据。
如下代码:
private static String importFile(String filePath, Long pos, int size) { StringBuffer strBuff = new StringBuffer(); RandomAccessFile raf = null; try { raf = new RandomAccessFile(filePath, "r"); long totalSize = raf.length(); if (pos >= totalSize) { return null; } raf.seek(pos); String line = null; int row = 0; while ((line = raf.readLine()) != null && row <= size - 1) { strBuff.append(new String(line.getBytes("iso-8859-1"), "GBK")); strBuff.append(" "); row++; } pos = raf.getFilePointer(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if (raf != null) { try { raf.close(); } catch (IOException e) { e.printStackTrace(); } } } return strBuff.toString(); }
如上代码,起始位置pos为字节数,假如我们需要从某一行开始读取所需的数据,除非你操作的文件的每一行的大小固定(即每一行的字节数是不变的),则可以利用行数转化为相应字节数来读取相应行的数据,否则的话,只能一行行的读取数据了。上述代码中,pos = raf.getFilePointer()获取下一行起始位置的字节数,保存该值则下次可直接利用raf.seek(pos)方法从该位置开始读取数据。
但是在实际的测试中发现,RandomAccessFile其其I/O性能较之其他的的同类性能差距很大,经测试其耗时为BufferedReader的几十倍,严重影响了程序的运行效率。
查看RandomAccessFile的源码:
public class RandomAccessFile implements DataOutput, DataInput { public final byte readByte() throws IOException { int ch = this.read(); if (ch < 0) throw new EOFException(); return (byte) (ch); } public native int read() throws IOException; public final void writeByte(int v) throws IOException { write(v); } public native void write(int b) throws IOException; }
RandomAccessFile每读/写一个字节就需对磁盘进行一次I/O操作。
而BufferedInputStream] 的源码:
public class BufferedInputStream extends FilterInputStream { private static int defaultBufferSize = 2048; protected byte buf[]; public BufferedInputStream(InputStream in, int size) { super(in); if (size <= 0) { throw new IllegalArgumentException("Buffer size <= 0"); } buf = new byte[size]; } public synchronized int read() throws IOException { ensureOpen(); if (pos >= count) { fill(); if (pos >= count) return -1; } return buf[pos++] & 0xff; // 直接从BUF[]中读取 } private void fill() throws IOException { if (markpos < 0) pos = 0; else if (pos >= buf.length) if (markpos > 0) { int sz = pos - markpos; System.arraycopy(buf, markpos, buf, 0, sz); pos = sz; markpos = 0; } else if (buf.length >= marklimit) { markpos = -1; pos = 0; } else { int nsz = pos * 2; if (nsz > marklimit) nsz = marklimit; byte nbuf[] = new byte[nsz]; System.arraycopy(buf, 0, nbuf, 0, pos); buf = nbuf; } count = pos; int n = in.read(buf, pos, buf.length - pos); if (n > 0) count = n + pos; } }
Buffered I/O putStream每读/写一个字节,若要操作的数据在BUF中,就直接对内存的buf[]进行读/写操作;否则从磁盘相应位置填充buf[],再直接对内存的buf[]进行读/写操作,绝大部分的读/写操作是对内存buf[]的操作。
内存存取时间单位是纳秒级(10E-9),磁盘存取时间单位是毫秒级(10E-3), 同样操作一次的开销,内存比磁盘快了百万倍。理论上可以预见,即使对内存操作上万次,花费的时间也远少对于磁盘一次I/O的开销。 显然后者是通过增加位于内存的BUF存取,减少磁盘I/O的开销,提高存取效率的,当然这样也增加了BUF控制部分的开销