我有得到每秒更新的日志文件。 我需要定期读取日志文件,一旦我做了阅读,我需要存储的文件指针位置在最后一行我读的结束,并在下次定期读我应该从这一点开始。
目前,我正在使用Java中的随机访问文件,并使用getFilePointer()
方法来获得他偏移值和seek()
方法去偏移位置。
但是,我看了大部分的文章,甚至在Java文档建议使用BufferredReader
一个文件的高效读取。 我怎样才能做到这一点(获取文件指针并移动到最后一行)使用BufferedReader
,或有任何其他有效的方式来实现这一任务呢?
一对夫妇的应工作方式:
- 打开使用一个FileInputStream,跳过()字节数目有关的文件,然后包裹流周围的BufferedReader(通过的InputStreamReader);
- 打开该文件(带有或的FileInputStream的RandomAccessFile),呼叫getChannel()在流/ RandomAccessFile的到信道上得到一个基本FileChannel,呼叫位置(),然后调用Channels.newInputStream()来从信道获取的输入流,这可以传递给InputStreamReader的 - > BufferedReader中。
我没有说实话异形这些,看看哪个是更好的性能明智的,但你应该看看那个在你的情况比较好。
与RandomAccessFile的问题本质上是它的readLine()方法是非常低效的。 如果它的方便您从RAF阅读和做自己的缓冲分割线,那么有什么错RAF每se--只是它的readLine()被执行不力
如果你正在读固定长度的文件尼尔·科菲的解决方案是好的。 然而,对于具有可变长度(数据接连不断地)也存在一些问题通过一个InputStreamReader直接的FileInputStream或FileChannel的InputStream使用的BufferedReader文件。 对于前考虑的情况下,
1)你想从一些偏移到当前文件长度读取数据。 所以,你使用BR上的FileInputStream / FileChannel(通过的InputStreamReader),并使用它的ReadLine方法。 但是,当你正在忙时读取数据,让说,一些数据得到了增加导致BF的的readLine比你预期的要读更多的数据(以前的文件长度)
2)你完成的readLine东西,但是当你尝试读取当前文件长度/通道位置的一些数据得到了突然增加导致当前文件长度/通道位置增加,但你已经看过比这个更少的数据。
在上述两种情况下,很难知道你已经阅读了实际的数据(你不能只使用数据的长度读取使用的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();
}
我也有类似的问题,我创建了这个类采取从BufferedStream线,并计算多少字节您已经使用至今读getBytes()
我们假设该行分隔符在默认情况下一个单字节,我们重新实例BufferedReader
为seek()
工作。
public class FileCounterIterator {
public Long position() {
return _position;
}
public Long fileSize() {
return _fileSize;
}
public FileCounterIterator newlineLength(Long newNewlineLength) {
this._newlineLength = newNewlineLength;
return this;
}
private Long _fileSize = 0L;
private Long _position = 0L;
private Long _newlineLength = 1L;
private RandomAccessFile fp;
private BufferedReader itr;
public FileCounterIterator(String filename) throws IOException {
fp = new RandomAccessFile(filename, "r");
_fileSize = fp.length();
this.seek(0L);
}
public FileCounterIterator seek(Long newPosition) throws IOException {
this.fp.seek(newPosition);
this._position = newPosition;
itr = new BufferedReader(new InputStreamReader(new FileInputStream(fp.getFD())));
return this;
}
public Boolean hasNext() throws IOException {
return this._position < this._fileSize;
}
public String readLine() throws IOException {
String nextLine = itr.readLine();
this._position += nextLine.getBytes().length + _newlineLength;
return nextLine;
}
}
文章来源: Efficient way of handling file pointers in Java? (Using BufferedReader with file pointer)