Решение Neil Coffey хорошо, если вы читают файлы фиксированной длины. Однако для файлов с переменной длиной (данные продолжают поступать) возникают проблемы с использованием BufferedReader непосредственно в входном потоке FileInputStream или FileChannel через InputStreamReader. Для экс рассмотрят случаи
1) Вы хотите читать данные из некоторого смещения текущей длиной файла. Таким образом, вы используете BR для FileInputStream/FileChannel (через InputStreamReader) и используете его метод readLine. Но пока вы заняты чтением данных, давайте скажем, что некоторые данные были добавлены, что приводит к тому, что readLine BF считывает больше данных, чем ожидалось (предыдущая длина файла)
2) Вы закончили читать статьи, но когда вы пытаетесь прочитать текущая длина файла/позиция канала, некоторые данные были добавлены внезапно, что приводит к увеличению текущей длины файла/позиции канала, но вы уже прочитали меньше данных, чем это.
В обоих вышеуказанных случаях трудно понять, фактические данные вы прочитали (вы не можете просто использовать длину данных для чтения с использованием Readline, потому что он пропускает некоторые символы, такие как возврат каретки)
Так лучше читать данные в буферизованных байтах и использовать обертку BufferedReader вокруг этого.Я написал несколько методов, как этот
/** 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();
}