package lcm.util; import java.io.*; public class BufferedRandomAccessFile { RandomAccessFile raf; static final int BUFFER_SIZE = 32768; // must be power of two! boolean bufferDirty = false; // buffer needs to be written back to disk? (If true, reads MUST use buffer.) byte[] buffer = new byte[BUFFER_SIZE]; long bufferOffset = -1; // what file offset does this buffer start at? int bufferLength = -1; // how many bytes of the buffer are valid? ( < BUFFER_SIZE near end of file) int bufferPosition = -1; // current file position in the buffer [0, BUFFER_SIZE-1] long fileLength; // length of the file /** Invariant: the current file position = bufferOffset + bufferPosition. This position is always stored inside the buffer, or this position is the byte after the current buffer (in which case the next read will re-fill the buffer. **/ public BufferedRandomAccessFile(File file, String mode) throws IOException { raf = new RandomAccessFile(file, mode); fileLength = raf.length(); bufferSeek(0); } public BufferedRandomAccessFile(String path, String mode) throws IOException { raf = new RandomAccessFile(path, mode); fileLength = raf.length(); bufferSeek(0); } public void close() throws IOException { flushBuffer(); raf.close(); } public long getFilePointer() { return bufferOffset + bufferPosition; } public long length() throws IOException { return fileLength; } int max(int a, int b) { return a > b ? a : b; } long max(long a, long b) { return a > b ? a : b; } long min(long a, long b) { return a < b ? a : b; } public void seek(long pos) throws IOException { bufferSeek(pos); } public void flush() throws IOException { flushBuffer(); } /** Writes the buffer if it contains any dirty data **/ void flushBuffer() throws IOException { if (!bufferDirty) return; raf.seek(bufferOffset); raf.write(buffer, 0, bufferLength); bufferDirty = false; } /** Performs a seek and fills the buffer accordingly. **/ void bufferSeek(long seekOffset) throws IOException { flushBuffer(); long newOffset = seekOffset - (seekOffset & (BUFFER_SIZE - 1L)); if (newOffset == bufferOffset) { bufferPosition = (int) (seekOffset - bufferOffset); return; } bufferOffset = newOffset; bufferLength = (int) min(BUFFER_SIZE, fileLength - bufferOffset); if (bufferLength < 0) bufferLength = 0; bufferPosition = (int) (seekOffset - bufferOffset); // we always ask for an amount that should be exactly available. raf.seek(bufferOffset); raf.readFully(buffer, 0, bufferLength); // System.out.printf("%08x %08x %08x %08x\n", seekOffset, bufferOffset, bufferPosition, bufferLength); } public final int read() throws IOException { if (bufferOffset + bufferPosition >= fileLength) throw new EOFException("EOF"); if (bufferPosition >= bufferLength) bufferSeek(bufferOffset + bufferPosition); return buffer[bufferPosition++]&0xff; } public boolean hasMore() throws IOException { return bufferPosition+bufferOffset < fileLength; } public byte peek() throws IOException { if (bufferPosition < bufferLength) return buffer[bufferPosition]; raf.seek(bufferOffset + bufferPosition); return raf.readByte(); } public void write(int v) throws IOException { write((byte) (v&0xff)); } public void writeBoolean(boolean b) throws IOException { write((byte) (b ? 1 : 0)); } public boolean readBoolean() throws IOException { return read()!=0; } public void writeShort(short v) throws IOException { write((byte) (v>>8)); write((byte) (v&0xff)); } public byte readByte() throws IOException { int v = read(); return (byte) (v&0xff); } public short readShort() throws IOException { short v = 0; v |= (read()<<8); v |= (read()); return v; } public void readFully(byte[] b, int offset, int length) throws IOException { while (length > 0) { int bufferAvailable = bufferLength - bufferPosition; int thiscopy = Math.min(bufferAvailable, length); if (thiscopy == 0) { flushBuffer(); if (bufferOffset + bufferPosition >= fileLength) throw new EOFException("EOF"); bufferSeek(bufferOffset + bufferLength); continue; } System.arraycopy(buffer, bufferPosition, b, offset, thiscopy); bufferPosition += thiscopy; offset += thiscopy; length -= thiscopy; } } public void readFully(byte[] b) throws IOException { readFully(b, 0, b.length); } public void writeInt(long v) throws IOException { write((byte) (v>>24)); write((byte) (v>>16)); write((byte) (v>>8)); write((byte) (v&0xff)); } public int readInt() throws IOException { int v = 0; v |= (read()<<24); v |= (read()<<16); v |= (read()<<8); v |= (read()); return v; } public void writeLong(long v) throws IOException { write((byte) (v>>56)); write((byte) (v>>48)); write((byte) (v>>40)); write((byte) (v>>32)); write((byte) (v>>24)); write((byte) (v>>16)); write((byte) (v>>8)); write((byte) (v&0xff)); } public long readLong() throws IOException { long v = 0; v |= (((long) read())<<56); v |= (((long) read())<<48); v |= (((long) read())<<40); v |= (((long) read())<<32); v |= (((long) read())<<24); v |= (((long) read())<<16); v |= (((long) read())<<8); v |= (((long) read())); return v; } public void writeFloat(float f) throws IOException { writeInt(Float.floatToIntBits(f)); } public float readFloat() throws IOException { return Float.intBitsToFloat(readInt()); } public void writeDouble(double f) throws IOException { writeLong(Double.doubleToLongBits(f)); } public double readDouble() throws IOException { return Double.longBitsToDouble(readLong()); } public void writeUTF(String s) throws IOException { writeShort((short) s.length()); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); // XXX BUG, not compliant with DataOutput write(s.charAt(i)&0xff); } } public String readUTF() throws IOException { // XXX BUG, not compliant with DataInput int length = readShort(); StringBuffer sb = new StringBuffer(length); for (int i = 0; i < length; i++) { sb.append((char) read()); } return sb.toString(); } /* public void write(byte src[], int offset, int writelen) throws IOException { bufferDirty = true; while (writelen > 0) { if (bufferPosition == BUFFER_SIZE) flushBuffer(); // how many bytes of this write will fit in the current buffer? long copylen = min(writelen, BUFFER_SIZE - bufferPosition); System.arraycopy(src, offset, buffer, bufferPosition, (int) copylen); bufferPosition += copylen; // have we made the file longer? if (bufferPosition > bufferLength) { length += bufferPosition - bufferLength; bufferLength = bufferPosition; } // get ready for the next copy writelen -= copylen; offset += copylen; } } */ public void write(byte src[], int offset, int writelen) throws IOException { for (int i = offset; i < offset + writelen; i++) write(src[i]); } public void write(byte v) throws IOException { bufferDirty = true; // they're doing a write within our current buffer. if (bufferPosition < bufferLength) { buffer[bufferPosition++] = v; return; } // they're increasing the size of the file, but it still fits inside our buffer if (bufferLength < BUFFER_SIZE) { buffer[bufferPosition++] = v; bufferLength++; fileLength++; return; } // they're doing a write, but we're out of buffer. flushBuffer(); bufferSeek(bufferOffset + bufferPosition); write(v); } public static boolean check; public String readLineCheck() throws IOException { if (!check) return readLine(); raf.seek(bufferOffset + bufferPosition); String s2 = raf.readLine(); String s1 = readLine(); System.out.println("braf: "+s1); System.out.println(" raf: "+s2); return s1; } public String readLine() throws IOException { StringBuilder sb = null; while (true) { int buffstart = bufferPosition; String piece = null; // suck as much out of this buffer as we can while (bufferPosition < bufferLength) { char c = (char) (buffer[bufferPosition++]&0xff); if (c=='\n') { piece = new String(buffer, buffstart, bufferPosition - buffstart - 1); break; } if (c=='\r') { piece = new String(buffer, buffstart, bufferPosition - buffstart - 1); // this logic is untested. if (false && bufferPosition + bufferPosition < fileLength) { // consume \r\n if it appears if (peek()=='\n') read(); } break; } } // if a piece has been created, then we have found a newline if (piece != null) { if (sb == null) return piece; sb.append(piece); return sb.toString(); } piece = new String(buffer, buffstart, bufferPosition - buffstart); if (sb == null) sb = new StringBuilder(); sb.append(piece); // EOF? if (bufferOffset + bufferPosition >= fileLength) { // return the string so far... if (sb.length() > 0) { return sb.toString(); } else return null; // EOF! } bufferSeek(bufferOffset + bufferPosition); } } public static void main(String args[]) { try { BufferedRandomAccessFile in = new BufferedRandomAccessFile(args[0],"r"); // BufferedRandomAccessFile out = new BufferedRandomAccessFile(args[1]); String l; while ((l = in.readLine())!=null) System.out.printf("^%s$\n", l); } catch (IOException ex) { System.out.println("Ex: "+ex); } } }