La soluzione di Neil Coffey è buona se stanno leggendo file di lunghezza fissa. Tuttavia, per i file che hanno una lunghezza variabile (i dati continuano ad arrivare) ci sono alcuni problemi con l'utilizzo di BufferedReader direttamente su FileInputStream o Filestream inputstream tramite un InputStreamReader. Per ex considerano i casi
1) si desidera leggere i dati da un po 'di offset per la lunghezza del file corrente. Quindi tu usi BR su FileInputStream/FileChannel (tramite un InputStreamReader) e usa il suo metodo readLine. Ma mentre si è occupato a leggere i dati lasciano dicono alcuni dati ricevuti aggiunto che provoca readLine di BF di leggere più dati di quanto ti aspettavi (il precedente lunghezza del file)
2) Hai finito readLine cose, ma quando si tenta di leggere la lunghezza corrente del file/posizione del canale alcuni dati sono stati aggiunti improvvisamente, il che fa aumentare la lunghezza del file corrente/la posizione del canale, ma avete già letto meno dati di questo.
In entrambi i casi di cui sopra, è difficile conoscere i dati effettivi di aver letto (non si può semplicemente utilizzare la lunghezza dei dati letti utilizzando readLine perché salta alcuni caratteri come ritorno a capo)
Così è meglio leggere i dati in byte bufferizzati e utilizzare un wrapper BufferedReader attorno a questo.Ho scritto alcuni metodi come questo
/** 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();
}
fonte
2013-11-08 19:54:40