Giải pháp của Neil Coffey là tốt nếu bạn đang đọc các tệp có độ dài cố định. Tuy nhiên đối với các tệp có độ dài biến đổi (dữ liệu tiếp tục đến), có một số vấn đề khi sử dụng BufferedReader trực tiếp trên InputInInStream hoặc FileChannel thông qua InputStreamReader. Ví dụ: hãy xem xét các trường hợp
1) Bạn muốn đọc dữ liệu từ một số bù đắp cho độ dài tệp hiện tại. Vì vậy, bạn sử dụng BR trên FileInputStream/FileChannel (thông qua InputStreamReader) và sử dụng phương thức readLine của nó. Nhưng trong khi bạn đang bận đọc dữ liệu hãy nói rằng một số dữ liệu đã được thêm vào làm cho readLine của BF đọc nhiều dữ liệu hơn so với những gì bạn mong đợi (độ dài tệp trước)
2) Bạn đã hoàn thành công cụ readLine nhưng khi bạn cố đọc chiều dài tập tin hiện tại/vị trí kênh một số dữ liệu đã được thêm đột ngột gây ra chiều dài tập tin hiện tại/vị trí kênh để tăng nhưng bạn đã đọc ít dữ liệu hơn điều này.
Trong cả hai trường hợp trên rất khó để biết các dữ liệu thực tế bạn đã đọc (bạn không thể chỉ sử dụng chiều dài của dữ liệu đọc sử dụng readLine vì nó bỏ qua một số ký tự như vận chuyển trở lại)
Vì vậy, nó là tốt hơn để đọc dữ liệu trong byte đệm và sử dụng một wrapper BufferedReader xung quanh này.Tôi đã viết một số phương pháp như thế này
/** 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();
}
Nguồn
2013-11-08 19:54:40