最近有一个银行数据漂白系统,要求操作人员在页面调用远端Linux服务器的shell,并将shell输出的信息保存到一个日志文件,前台页面要实时显示日志文件的内容.这个问题难点在于如何判断哪些数据是新增加的,通过查看JDK 的帮助文档,java.io.RandomAccessFile
可以解决这个问题.为了模拟这个问题,编写LogSvr和 LogView类,LogSvr不断向mock.log日志文件写数据,而 LogView则实时输出日志变化部分的数据.

代码1:日志产生类

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
*<p>title: 日志服务器</p>
*<p>Description: 模拟日志服务器</p>
*<p>CopyRight: CopyRight (c) 2010</p>
*<p>Company: 99bill.com</p>
*<p>Create date: 2010-6-18</P>
*@author Tank Zhang<tank.zhang@99bill.com>
*@version v0.1 2010-6-18
*/
public class LogSvr { private SimpleDateFormat dateFormat =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /**
* 将信息记录到日志文件
* @param logFile 日志文件
* @param mesInfo 信息
* @throws IOException
*/
public void logMsg(File logFile,String mesInfo) throws IOException{
if(logFile == null) {
throw new IllegalStateException("logFile can not be null!");
}
Writer txtWriter = new FileWriter(logFile,true);
txtWriter.write(dateFormat.format(new Date()) +"\t"+mesInfo+"\n");
txtWriter.flush();
} public static void main(String[] args) throws Exception{ final LogSvr logSvr = new LogSvr();
final File tmpLogFile = new File("mock.log");
if(!tmpLogFile.exists()) {
tmpLogFile.createNewFile();
}
//启动一个线程每5秒钟向日志文件写一次数据
ScheduledExecutorService exec =
Executors.newScheduledThreadPool(1);
exec.scheduleWithFixedDelay(new Runnable(){
public void run() {
try {
logSvr.logMsg(tmpLogFile, " 99bill test !");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}, 0, 5, TimeUnit.SECONDS);
}
}

代码2:显示日志的类

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; public class LogView {
private long lastTimeFileSize = 0; //上次文件大小
/**
* 实时输出日志信息
* @param logFile 日志文件
* @throws IOException
*/
public void realtimeShowLog(File logFile) throws IOException{
//指定文件可读可写
final RandomAccessFile randomFile = new RandomAccessFile(logFile,"rw");
//启动一个线程每10秒钟读取新增的日志信息
ScheduledExecutorService exec =
Executors.newScheduledThreadPool(1);
exec.scheduleWithFixedDelay(new Runnable(){
public void run() {
try {
//获得变化部分的
randomFile.seek(lastTimeFileSize);
String tmp = "";
while( (tmp = randomFile.readLine())!= null) {
System.out.println(new String(tmp.getBytes("ISO8859-1")));
}
lastTimeFileSize = randomFile.length();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}, 0, 1, TimeUnit.SECONDS);
} public static void main(String[] args) throws Exception {
LogView view = new LogView();
final File tmpLogFile = new File("mock.log");
view.realtimeShowLog(tmpLogFile);
} }

执行LogSvr类,LogSvr类会启动一个线程,每5秒钟向mock.log日志文件写一次数据,然后再执行LogView类,LogView每隔1秒钟读一次,如果数据有变化则输出变化的部分.

结果输出:

2010-06-19 17:25:54  99bill test !
2010-06-19 17:25:59  99bill test !
2010-06-19 17:26:04  99bill test !
2010-06-19 17:26:09  99bill test !
2010-06-19 17:26:14  99bill test !
2010-06-19 17:26:19  99bill test !

http://sunnylocus.iteye.com/blog/694666?page=2#comments

如果读取的日志文件,会被重命令或打开的操作。在使用RandomAccessFile每次读取后,执行close操作即可

在实习的公司碰到一个古怪的需求:在一台服务器上写日志文件,每当日志文件写到一定大小时,比如是1G,会将这个日志文件改名成另一个名字,并新建一个与原文件名相同的日志文件,再往这个新建的日志文件里写数据;要求写一个程序能实时地读取日志文件中的内容,并且不能写日志操作、重命名操作。

首先,这个问题在windows下几乎无解,因为一个程序打开了一个文件,再要对文件重命名是不可能的;而在Linux下,可以得到完美解决。因为Linux的文件系统有别于windows,Linux不使用文件名,而是使用inode号码来识别文件。关于inode的详细介绍参看理解inode

Linux下文件夹下创建文件个数是有限的,即inode数是有限定的

更新:在windows下实时读取也是可行的

RandomAccessFile类中seek方法可以从指定位置读取文件,可以用来实现文件实时读取。JDK文档对RandomAccessFile的介绍

Instances of this class support both reading and writing to a random access file. A random access file behaves like a large array of bytes stored in the file system. There is a kind of cursor, or index into the implied array, called the file pointer; input operations read bytes starting at the file pointer and advance the file pointer past the bytes read. If the random access file is created in read/write mode, then output operations are also available; output operations write bytes starting at the file pointer and advance the file pointer past the bytes written. Output operations that write past the current end of the implied array cause the array to be extended.

在每一次读取后,close一下就不会影响重命名操作了。

seek

public void seek(long pos)
throws IOException
Sets the file-pointer offset, measured from the beginning of this file, at which the next read or write occurs. The offset may be set beyond the end of the file. Setting the offset beyond the end of the file does not change the file length. The file length will change only by writing after the offset has been set beyond the end of the file.

Parameters:
pos - the offset position, measured in bytes from the beginning of the file, at which to set the file pointer.
Throws:
IOException - if pos is less than 0 or if an I/O error occurs.

getFilePointer

public long getFilePointer()
throws IOException
Returns the current offset in this file.

Returns:
the offset from the beginning of the file, in bytes, at which the next read or write occurs.
Throws:
IOException - if an I/O error occurs.

import java.io.File;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.text.SimpleDateFormat;
import java.util.Date; public class LogReader implements Runnable {
private File logFile = null;
private long lastTimeFileSize = 0; // 上次文件大小
private static SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss"); public LogReader(File logFile) {
this.logFile = logFile;
lastTimeFileSize = logFile.length();
} /**
* 实时输出日志信息
*/
public void run() {
while (true) {
try {
RandomAccessFile randomFile = new RandomAccessFile(logFile, "r");
randomFile.seek(lastTimeFileSize);
String tmp = null;
while ((tmp = randomFile.readLine()) != null) {
System.out.println(dateFormat.format(new Date()) + "\t"
+ tmp);
}
lastTimeFileSize = randomFile.length();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} }

http://www.cnblogs.com/en-heng/p/3926708.html

RandomAccessFile实时读取大文件(转)的更多相关文章

  1. Java实时读取日志文件

    古怪的需求 在实习的公司碰到一个古怪的需求:在一台服务器上写日志文件,每当日志文件写到一定大小时,比如是1G,会将这个日志文件改名成另一个名字,并新建一个与原文件名相同的日志文件,再往这个新建的日志文 ...

  2. java读取 500M 以上文件,java读取大文件

    java 读取txt,java读取大文件 设置缓存大小BUFFER_SIZE ,Config.tempdatafile是文件地址 来源博客http://yijianfengvip.blog.163.c ...

  3. java 读取txt,java读取大文件

    java 读取txt,java读取大文件 package com.bbcmart.util; import java.io.File;import java.io.RandomAccessFile;i ...

  4. Java快速读取大文件

    Java快速读取大文件 最近公司服务器监控系统需要做一个东西来分析Java应用程序的日志. 第一步探索: 首先我想到的是使用RandomAccessFile,因为他可以很方便的去获取和设置文件指针,下 ...

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

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

  6. java读取大文件

    1  多线程 2  java内存映射读取大文件

  7. php使用file函数、fseek函数读取大文件效率分析

    php读取大文件可以使用file函数和fseek函数,但是二者之间效率可能存在差异,本文章向大家介绍php file函数与fseek函数实现大文件读取效率对比分析,需要的朋友可以参考一下. 1. 直接 ...

  8. Java多线程读取大文件

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

  9. PHP读取大文件的几种方法介绍

    读取大文件一直是一个头痛的问题,我们像使用php开发读取小文件可以直接使用各种函数实现,但一到大文章就会发现常用的方法是无法正常使用或时间太长太卡了,下面我们就一起来看看关于php读取大文件问题解决办 ...

随机推荐

  1. Python学习入门基础教程(learning Python)--2.3.1 Python传参函数设计

    本节主要讨论设计传递多个参数子函数的设计方法. 在2.3节里我们讨论了如何自己设计一个带参数的子函数的设计方法,现在我们研究一下如何传递两个及以上参数的设计方法. 函数为何要带参数呢?其实原因很简单, ...

  2. java 常用的包 默认导入的包

    1.java.lang----包含一些Java语言的核心类,如String.Math.Integer.System和Thread,提供常用功能. 2.java.awt----包含了构成抽象窗口工具集( ...

  3. Cocos2d-x Layout简单使用

    1. Text* alert = Text::create("Layout", "fonts/Marker Felt.ttf", 30 ); alert-> ...

  4. Oracle错误——ORA-03113:在通信信道文件的末尾 解决方案

    起源 今天跟往常一样,登陆PL/SQL,确登陆失败,出现一个错误"ORA-01034"和"ORA-27101"如图: 然后就就通过命令提示符去登陆Oracle, ...

  5. Web服务器Raspkate的RESTful API

    基于轻量型Web服务器Raspkate的RESTful API的实现 在上一篇文章中,我们已经了解了Raspkate这一轻量型Web服务器,今天,我们再一起了解下如何基于Raspkate实现简单的RE ...

  6. 关于扩展IP地址空间的几个方案的探讨

    摘  要:在IP地址紧缺的背景下,IPv6.NAPT.SuIP几种解决方案应运而生.分析.比较几种方案后,可知SuIP是最佳方案. 关键词:IPv6:NAPT:SuIP:IP地址空间扩展 The In ...

  7. 深入理解计算机系统之旅(四)处理器(CPU)的体系结构

    1.前言 处理器是很复杂的系统,它不是一蹴而就的,它是经过不断的升级.更新.设计之后的产物,而且如今还在保持着不断的更新. 处理器仅仅能运行一系列的指令,每条指令都仅仅是运行某个简单的操作,比方数字相 ...

  8. 设计模式(一)工厂模式Factory(创建类型)

    设计模式一 工厂模式Factory 在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的.可是在一些情况下, new操作符直接生成对象会带来一些问题. ...

  9. win7 64bit+vs2010 操作注册表

    注册表五个根键 HKEY_CLASSES_ROOT--管理文件系统  HKEY_LOCAL_MACHINE--管理当前系统硬件配置  HKEY_LOCAL_USER--管理系统当前用户配置  HKEY ...

  10. 【SICP读书笔记(四)】练习2.27 --- 表序列reverse的扩展:树结构的deep-reverse

    题目要求是,修改练习2.18所做的reverse过程,得到一个deep-reverse过程.它以一个表为参数,返回另一个表作为值,结果表中的元素反转过来,其中的子树也反转. 例如: (define x ...