La solución de Neil Coffey es buena si están leyendo archivos de longitud fija. Sin embargo, para los archivos que tienen una longitud variable (los datos siguen llegando) existen algunos problemas con el uso de BufferedReader directamente en FileInputStream o FileChannel inputstream a través de un InputStreamReader. Para ex consideran los casos
1) desea leer datos de alguna desviación de la longitud del archivo actual. Entonces usas BR en FileInputStream/FileChannel (a través de un InputStreamReader) y usas su método readLine. Pero mientras está ocupado leyendo los datos, digamos que se agregaron algunos datos que hacen que readLine de BF lea más datos de los esperados (la longitud del archivo anterior)
2) Terminó de leer las líneas pero cuando intenta leer la longitud actual del archivo/posición del canal algunos datos se agregaron repentinamente, lo que hace que aumente la longitud actual del archivo/posición del canal, pero ya ha leído menos datos que este.
En los dos casos anteriores, es difícil conocer los datos reales que haya leído (no se puede simplemente utilizar la longitud de los datos leídos usando readLine porque omite algunos caracteres como retorno de carro)
Así es mejor leer los datos en bytes almacenados en búfer y usar un contenedor BufferedReader alrededor de esto.Escribí algunos métodos como éste
/** Read data from offset to length bytes in RandomAccessFile using BufferedReader
* @param offset
* @param length
* @param accessFile
* @throws IOException
*/
public static void readBufferedLines(long offset, long length, RandomAccessFile accessFile) throws IOException{
if(accessFile == null) return;
int bufferSize = BYTE_BUFFER_SIZE;// constant say 4096
if(offset < length && offset >= 0){
int index = 1;
long curPosition = offset;
/*
* iterate (length-from)/BYTE_BUFFER_SIZE times to read into buffer no matter where new line occurs
*/
while((curPosition + (index * BYTE_BUFFER_SIZE)) < length){
accessFile.seek(offset); // seek to last parsed data rather than last data read in to buffer
byte[] buf = new byte[bufferSize];
int read = accessFile.read(buf, 0, bufferSize);
index++;// Increment whether or not read successful
if(read > 0){
int lastnewLine = getLastLine(read,buf);
if(lastnewLine <= 0){ // no new line found in the buffer reset buffer size and continue
bufferSize = bufferSize+read;
continue;
}
else{
bufferSize = BYTE_BUFFER_SIZE;
}
readLine(buf, 0, lastnewLine); // read the lines from buffer and parse the line
offset = offset+lastnewLine; // update the last data read
}
}
// Read last chunk. The last chunk size in worst case is the total file when no newline occurs
if(offset < length){
accessFile.seek(offset);
byte[] buf = new byte[(int) (length-offset)];
int read = accessFile.read(buf, 0, buf.length);
if(read > 0){
readLine(buf, 0, read);
offset = offset+read; // update the last data read
}
}
}
}
private static void readLine(byte[] buf, int from , int lastnewLine) throws IOException{
String readLine = "";
BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(buf,from,lastnewLine)));
while((readLine = reader.readLine()) != null){
//do something with readLine
System.out.println(readLine);
}
reader.close();
}
private static int getLastLine(int read, byte[] buf) {
if(buf == null) return -1;
if(read > buf.length) read = buf.length;
while(read > 0 && !(buf[read-1] == '\n' || buf[read-1] == '\r')) read--;
return read;
}
public static void main(String[] args) throws IOException {
RandomAccessFile accessFile = new RandomAccessFile("C:/sri/test.log", "r");
readBufferedLines(0, accessFile.length(), accessFile);
accessFile.close();
}