Java中处理文件指针的有效方法? (使用 BufferedReader 和文件指针)

问题描述 投票:0回答:3

我有一个每秒更新的日志文件。 我需要定期读取日志文件,一旦执行读取,我需要将文件指针位置存储在我读取的最后一行的末尾,并且在下一个定期读取中我应该从该点开始。

目前,我正在Java中使用随机访问文件,并使用

getFilePointer()
方法获取偏移值,并使用
seek()
方法转到偏移位置。

但是,我读过大多数文章,甚至 Java 文档建议使用

BufferredReader
来高效读取文件。 我怎样才能使用
BufferedReader
来实现这一点(获取文件指针并移动到最后一行),或者是否有其他有效的方法来实现此任务?

java file pointers buffered
3个回答
4
投票

有几种可行的方法:

  • 使用 FileInputStream 打开文件,skip() 相关字节数,然后将 BufferedReader 包装在流周围(通过 InputStreamReader);
  • 打开文件(使用FileInputStream或RandomAccessFile),在流/RandomAccessFile上调用getChannel()以获取底层FileChannel,在通道上调用position(),然后调用Channels.newInputStream()以从通道获取输入流,您可以将其传递给 InputStreamReader -> BufferedReader。

我还没有诚实地分析这些,看看哪个在性能方面更好,但你应该看看哪个更适合你的情况。

RandomAccessFile 的问题本质上是它的 readLine() 方法效率很低。如果您可以方便地从 RAF 中读取数据并进行自己的缓冲来分割行,那么 RAF 本身并没有什么问题——只是它的 readLine() 实现得不好


1
投票

如果您正在阅读固定长度的文件,Neil Coffey 的解决方案很好。然而,对于具有可变长度的文件(数据不断传入),直接在

BufferedReader
或通过
FileInputStream
输入流使用
FileChannel
会出现一些问题。对于前考虑案例

    您想要从某个偏移量读取数据到当前文件长度。因此,您在
  1. InputStreamReader

    /

    FileInputStream
    (通过
    FileChannel
    )上使用 BR 并使用其 readLine 方法。但是,当您忙于读取数据时,假设添加了一些数据,这导致 BF 的 readLine 读取的数据比您预期的要多(之前的文件长度)
    
    

  2. 您完成了 readLine 内容,但是当您尝试读取当前文件长度/通道位置时,突然添加了一些数据,这导致当前文件长度/通道位置增加,但您已经读取的数据少于此。
  3. 在上述两种情况下,很难知道您实际读取的数据(您不能只使用使用 readLine 读取的数据长度,因为它会跳过一些字符,例如回车符)

因此,最好以缓冲字节的形式读取数据,并使用

InputStreamReader

包装器来解决这个问题。我写了一些这样的方法

BufferedReader



0
投票
/** 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(); }

来计算到目前为止已读取的字节数。我们假设行分隔符默认为单个字节,并且我们重新实例化

getBytes()
以使
BufferedReader
正常工作。
seek()

	
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.