Neil Coffey的解决方案适用于读取固定长度文件。但是对于具有可变长度(数据不断进入)的文件,直接在FileInputStream或FileChannel输入流上使用BufferedReader或通过InputStreamReader使用其readLine方法存在一些问题。例如,考虑以下情况:
1)您想要从某个偏移量读取数据到当前文件长度。因此,您在FileInputStream/FileChannel(通过InputStreamReader)上使用BR,并使用其readLine方法。但是,当您正在忙于读取数据时,假设添加了一些数据,这会导致BF的readLine读取比您预期的(之前的文件长度)更多的数据。
2)您完成了readLine操作,但是当您尝试读取当前文件长度/通道位置时,突然添加了一些数据,这会导致当前文件长度/通道位置增加,但是您已经读取的数据比这少。
在上述两种情况中,很难知道实际读取的数据(您不能仅使用使用readLine读取的数据长度,因为它跳过了一些字符,如回车符)。
因此,最好以缓冲字节方式读取数据,并在此周围使用BufferedReader包装器。我编写了一些类似于此的方法。
public static void readBufferedLines(long offset, long length, RandomAccessFile accessFile) throws IOException{
if(accessFile == null) return;
int bufferSize = BYTE_BUFFER_SIZE;
if(offset < length && offset >= 0){
int index = 1;
long curPosition = offset;
while((curPosition + (index * BYTE_BUFFER_SIZE)) < length){
accessFile.seek(offset);
byte[] buf = new byte[bufferSize];
int read = accessFile.read(buf, 0, bufferSize);
index++;
if(read > 0){
int lastnewLine = getLastLine(read,buf);
if(lastnewLine <= 0){
bufferSize = bufferSize+read;
continue;
}
else{
bufferSize = BYTE_BUFFER_SIZE;
}
readLine(buf, 0, lastnewLine);
offset = offset+lastnewLine;
}
}
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;
}
}
}
}
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){
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();
}