Java快速读取大文件

最近公司服务器监控系统需要做一个东西来分析Java应用程序的日志。

第一步探索:

首先我想到的是使用RandomAccessFile,因为他可以很方便的去获取和设置文件指针,下面是我的代码。

package cn.mucang.exception.analyzer;

import cn.mucang.exception.analyzer.analyze.LogAnalyzer;
import cn.mucang.exception.analyzer.config.AnalyseConfig;
import cn.mucang.exception.analyzer.support.DefaultLogLineBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile; /**
* @author Gao Youbo
* @since 2015/3/16.
*/
public class LogUtils { private static final Logger LOG = LoggerFactory.getLogger(LogUtils.class); /**
* 分析日志
*
* @param analyzer 分析器
* @throws IOException
*/
public static void analyse(LogAnalyzer analyzer) throws IOException {
AnalyseConfig analyseConfig = analyzer.getAnalyseConfig();
File file = new File(analyseConfig.getPath());
LOG.info("开始分析日志文件...{}", file.getAbsolutePath());
if (!file.exists()) {
throw new IOException("日志文件不存在:" + analyseConfig);
}
if (analyseConfig.getFilePointer() < 0) {
analyseConfig.setFilePointer(0);
} FileInputStream stream = new FileInputStream(file);
InputStreamReader reader = new InputStreamReader(stream);
BufferedReader bufferedReader = new BufferedReader(reader);
try (RandomAccessFile logFile = new RandomAccessFile(file, "r")) {
long length = logFile.length();
analyzer.getAnalyseConfig().setFileLenght(length); //设置文件字节长度
if (analyseConfig.getFilePointer() > length) {
throw new IllegalArgumentException("开始指针位置越界");
} else {
logFile.seek(analyseConfig.getFilePointer());
}
String line; //行数据
int lineNumber = analyseConfig.getLineNumber(); //行号
DefaultLogLineBuilder lb = null;
long start = System.currentTimeMillis();
while ((line = logFile.readLine()) != null) {
bufferedReader.readLine();
lineNumber++;
long filePointer = logFile.getFilePointer();
if (ParseUtils.isNewLine(lineNumber, line)) {
if (lb != null) {
analyzer.analyse(lb.getLogLine());
}
lb = new DefaultLogLineBuilder();
}
if (lb != null) {
lb.append(lineNumber, filePointer, line);
if (length == logFile.getFilePointer()) { //文档读取完了,调用一下分析
analyzer.analyse(lb.getLogLine());
}
}
if (lineNumber % 10000 == 0) {
long end = System.currentTimeMillis();
System.out.println(String.format("line=%s, used=%sms", lineNumber, end - start));
start = System.currentTimeMillis();
}
}
}
} }

下面看一下性能,分析一万行日志平均需要1500毫秒,因为我的日志分析使用到了正则,开始速度慢我以为是大量的正则运算造成的。

第二部探索:

我自己写了一个LogReader,自己控制指针位置。下面看一下代码:

package cn.mucang.exception.analyzer;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader; /**
* @author Gao Youbo
* @since 2015-03-25 09:02
*/
public class LogReader implements Closeable {
/**
* 文件大小
*/
private long length;
/**
* 文件指针位置
*/
private long filePointer;
private FileInputStream inputStream;
private InputStreamReader inputStreamReader;
private BufferedReader bufferedReader; public LogReader(File logFile) throws FileNotFoundException {
this.inputStream = new FileInputStream(logFile);
this.inputStreamReader = new InputStreamReader(inputStream);
this.bufferedReader = new BufferedReader(inputStreamReader);
this.length = logFile.length();
} public int read() throws IOException {
filePointer++;
return bufferedReader.read();
} public String readLine() throws IOException {
StringBuffer input = new StringBuffer();
int c = -1;
boolean eol = false; //end of line
while (!eol) {
switch (c = read()) {
case -1:
case '\n':
eol = true;
break;
case '\r':
eol = true;
long cur = getFilePointer();
if ((read()) != '\n') {
skip(cur);
}
default:
input.append((char) c);
break;
}
}
if ((c == -1) && (input.length() == 0)) {
return null;
}
return input.toString();
} /**
* 获取当前读取到的指针
*
* @return
* @throws IOException
*/
public long getFilePointer() throws IOException {
return filePointer;
} /**
* 从当前位置跳过n个char
*
* @param n
* @return 实际跳过多少个char
* @throws IOException
*/
public long skip(long n) throws IOException {
return inputStreamReader.skip(n);
} /**
* 返回日志文件的大小
*
* @return
*/
public long length() {
return length;
} @Override
public void close() throws IOException {
if (bufferedReader != null) {
bufferedReader.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (inputStream != null) {
inputStream.close();
}
}
} package cn.mucang.exception.analyzer; import cn.mucang.exception.analyzer.analyze.LogAnalyzer;
import cn.mucang.exception.analyzer.config.AnalyseConfig;
import cn.mucang.exception.analyzer.support.DefaultLogLineBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.io.File;
import java.io.IOException; /**
* @author Gao Youbo
* @since 2015/3/16.
*/
public class LogUtils { private static final Logger LOG = LoggerFactory.getLogger(LogUtils.class); /**
* 分析日志
*
* @param analyzer 分析器
* @throws java.io.IOException
*/
public static void analyse(LogAnalyzer analyzer) throws IOException {
AnalyseConfig analyseConfig = analyzer.getAnalyseConfig();
File file = new File(analyseConfig.getPath());
System.out.println(file.getAbsolutePath());
LOG.info("开始分析日志文件...{}", file.getAbsolutePath());
if (!file.exists()) {
throw new IOException("日志文件不存在:" + analyseConfig);
}
if (analyseConfig.getFilePointer() < 0) {
analyseConfig.setFilePointer(0);
}
try (LogReader logReader = new LogReader(file)) {
long length = logReader.length();
analyzer.getAnalyseConfig().setFileLenght(length); //设置文件字节长度
if (analyseConfig.getFilePointer() > length) {
throw new IllegalArgumentException("开始指针位置越界");
} else {
logReader.skip(analyseConfig.getFilePointer());
}
String line; //行数据
int lineNumber = analyseConfig.getLineNumber(); //行号
DefaultLogLineBuilder lb = null;
long start = System.currentTimeMillis();
while ((line = logReader.readLine()) != null) {
lineNumber++;
long filePointer = logReader.getFilePointer();
if (ParseUtils.isNewLine(lineNumber, line)) {
if (lb != null) {
analyzer.analyse(lb.getLogLine());
}
lb = new DefaultLogLineBuilder();
}
if (lb != null) {
lb.append(lineNumber, filePointer, line);
if (length == filePointer) { //文档读取完了,调用一下分析
analyzer.analyse(lb.getLogLine());
}
}
if (lineNumber % 10000 == 0) {
long end = System.currentTimeMillis();
System.out.println(String.format("line=%s, used=%s", lineNumber, end - start));
start = System.currentTimeMillis();
}
}
}
}
}

接下来是测试的性能:

日志解析速度提高了10倍。

Java快速读取大文件的更多相关文章

  1. C++快速读取大文件

    debug的时候需要等很长时间读模型,查资料发现了两种快速读取大文件的方法. test 1:每次读一个字符串 test 2.3一次读取整个文件 {//test 1 string buf; clock_ ...

  2. PHP几个快速读取大文件例子

    PHP几个快速读取大文件例子 感谢 把我给崩了 的投递 时间:2014-10-16 来源:三联 在PHP中,对于文件的读取时,最快捷的方式莫过于使用一些诸如file.file_get_contents ...

  3. Java高效读取大文件

    1.概述 本教程将演示如何用Java高效地读取大文件.这篇文章是Baeldung (http://www.baeldung.com/) 上“Java——回归基础”系列教程的一部分. 2.在内存中读取 ...

  4. Java高效读取大文件(转)

    1.概述 本教程将演示如何用Java高效地读取大文件.这篇文章是Baeldung(http://www.baeldung.com/) 上“Java——回归基础”系列教程的一部分. 2.在内存中读取 读 ...

  5. Java多线程读取大文件

    前言 今天是五一假期第一天,按理应该是快乐玩耍的日子,但是作为一个北漂到京师的开发人员,实在难想出去那玩耍.好玩的地方比较远,近处又感觉没意思.于是乎,闲着写篇文章,总结下昨天写的程序吧. 昨天下午朋 ...

  6. PHP如何快速读取大文件

    在PHP中,对于文件的读取时,最快捷的方式莫过于使用一些诸如file.file_get_contents之类的函数,简简单单的几行代码就能 很漂亮的完成我们所需要的功能.但当所操作的文件是一个比较大的 ...

  7. 【转】PHP如何快速读取大文件

    在PHP中,对于文件的读取时,最快捷的方式莫过于使用一些诸如file.file_get_contents之类的函数,简简单单的几行代码就能 很漂亮的完成我们所需要的功能.但当所操作的文件是一个比较大的 ...

  8. java nio 读取大文件

    package com.yao.bigfile; import java.io.File; import java.io.IOException; import java.io.RandomAcces ...

  9. Java读取大文件的高效率实现

    1.概述 本教程将演示如何用Java高效地读取大文件.这篇文章是Baeldung (http://www.baeldung.com/) 上“Java——回归基础”系列教程的一部分. 2.在内存中读取 ...

随机推荐

  1. 论文阅读(Chenyi Chen——【ACCV2016】R-CNN for Small Object Detection)

    Chenyi Chen--[ACCV2016]R-CNN for Small Object Detection 目录 作者和相关链接 方法概括 创新点和贡献 方法细节 实验结果 总结与收获点 参考文献 ...

  2. Enable MFA for a user

    If you are root/admin account, in order to configure a virtual MFA device, you must have physical ac ...

  3. 要“jquery”ScriptResourceMapping。请添加一个名为 jquery (区分大小写)的 ScriptResourceMapping。”的解决办法。

    1.在网站根目录下新建一scripts文件夹,向里边添加jquery-1.7.2.min.js和jquery-1.7.2.js(可根据自己需要使用不同的版本),      2.在根目录下添加全局应用程 ...

  4. express源码剖析2

    当使用express时,代码会这样写: var express = require('express'); 如果创建一个express的应用,代码会这样写: var app = express(); ...

  5. SolrCloud应用简介

    1.windows下启动实例工程 官网下载solr后解压到本地硬盘,在sol/bin目录下打开命令行窗口,然后测试以下命令: solr -e cloud 启动例子中的solrcould,进入交互界面, ...

  6. 帝国cms &lt;!--list.var1--&gt;产生不同样式

    制作帝国列表模板正常情况下 列表内容模板(list.var) (*) 写 <li class=''>[!--title--]<a href='[!--titleurl--]'> ...

  7. 食物链-HZUN寒假集训

    食物链 总时间限制: 1000ms 内存限制: 65536kB 描述 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动 ...

  8. pycharm 安装和首次使用

    由于本人也是开发语言的学习小白,所以对于开发时使用的工具也不算太熟悉,不过这里还是要推荐一下本人使用过 的两款工具: 1.pycharm  :2.eclipse 这是我用的比较顺手的两个工具当然这两个 ...

  9. 可视化神器--Plotly

    数据分析离不开数据可视化.我们最常用的就是pandas,matplotlib,pyecharts当然还有Tableau,看到一篇文章介绍plotly制图后我也跃跃欲试,查看了相关资料开始学习plotl ...

  10. 从零开始一个http服务器(六)-多路复用和压力测试

    从零开始一个http服务器(六)-多路复用和压力测试 代码地址 : https://github.com/flamedancer/cserver git checkout step6 运行: make ...