当我们在读取文件的时候,通常都是从前向后读取,那如果要读取文件的最后一行内容,要如何操作呢?
顺序遍历读取,直到文件最后一行
publicstaticStringreadLastLineV0(Filefile){StringlastLine="";try(BufferedReaderbufferedReader=newBufferedReader(newFileReader(file))){StringcurrentLine="";while((currentLine=bufferedReader.readLine())!=null){lastLine=currentLine;}}catch(Exceptione){log.error("filereaderror,msg:{}",e.getMessage(),e);}returnlastLine;}
该方式很简单,从前向后读取即可,直到最后一行。
利用RandomAccessFile指定位置,从后向前读取
publicstaticStringreadLastLineV1(Filefile){//存储结果StringBuilderbuilder=newStringBuilder();try(RandomAccessFilerandomAccessFile=newRandomAccessFile(file,"r")){//指针位置开始为0,所以最大长度为length-1longfileLastPointer=randomAccessFile.length()-1;//从后向前读取文件for(longfilePointer=fileLastPointer;filePointer!=-1;filePointer--){//移动指针指向randomAccessFile.seek(filePointer);intreadByte=randomAccessFile.readByte();if(0xA==readByte){//LF='\n'=0x0A换行if(filePointer==fileLastPointer){//如果是最后的换行,过滤掉continue;}break;}if(0xD==readByte){//CR='\r'=0x0D回车if(filePointer==fileLastPointer-1){//如果是倒数的回车也过滤掉continue;}break;}builder.append((char)readByte);}}catch(Exceptione){log.error("filereaderror,msg:{}",e.getMessage(),e);}returnbuilder.reverse().toString();}
该方式主要是利用RandomAccessFile可以seek到指定位置读取的方式。从文件的最后向前读取,当遇到0xA(换行)或者0xD(回车)时,利用StringBuilder缓存一下读取到的数据,最后将数据reverse即是最后一行数据。
利用commons-io中的ReversedLinesFileReader
maven导入依赖
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.7</version></dependency>
publicstaticStringreadLastLineV2(Filefile){StringlastLine="";try(ReversedLinesFileReaderreversedLinesReader=newReversedLinesFileReader(file,Charset.defaultCharset())){lastLine=reversedLinesReader.readLine();}catch(Exceptione){log.error("filereaderror,msg:{}",e.getMessage(),e);}returnlastLine;}
该方式可以直接读取到最后一行数据。有兴趣的同学可以自行看一下源码,非常少。它的实现是思路是先将文件拆成多个FilePart。读取位置定位是基于SeekableByteChannel的position方法。而FilePart的readLine实现中,可以一次读取多个bytes。
总结
以上三种读取文件最后一行的方法中,推荐使用commons-io中的ReversedLinesFileReader,使用方式也比较简单。