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);
}
}
}