近日客户提出需求,需要调研如何使用Java来读取Windows日志文件(类型:应用程序,安全,Setup,系统)。
一番调研以后,在仅使用java的基础上读取系统日志文件不太可能(就个人调研结果来看),原因如下:
1)系统日志文件(.evtx)是以机器码形式存储的,使用C++等语言(直接与机器打交道),可以直接读取且解析其内容。而使用Java(JVM的存在,字节码级别的编译),意味这我们需要知道文件机器码的具体转化规则方可解析(微软没有提供相关的内容)
1 是否可以使用Java来调用C++方法?
JNA(Java Native Access)是可以让Java调用C++生成的DLL(动态链接库),将C++中的方法,以Java接口的方式来实现。与JNI不同的是,JNA可以直接调用本地的一些现有的库,而JNI则必须自己手动创建且生成动态链接库再进行调用。但是也有不足之处,JNA只能做到Java调用C++的代码,而JNI还允许C++调用Java的代码。具体的选择就看具体需求了。
2 JNA源码下载
JNA下载
两个jar包都需要下载,并且导入到自己的项目之中。
3 编写测试方法
项目目录:
测试方法:
@Test
public void testReadEventLogEntries2() {
Advapi32Util.EventLogIterator iter = new Advapi32Util.EventLogIterator("Application");
while (iter.hasNext()) {
Advapi32Util.EventLogRecord record = iter.next();
StringBuffer data = new StringBuffer();
String[] str = record.getStrings();
if (str == null) {
//若任务描述为空
} else {
for (String s : str) {
data.append(s);
}
}
WinNT.EVENTLOGRECORD record1 = record.getRecord();
//get event generated time
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String generatedTime = simpleDateFormat.format(new Date(record1.TimeGenerated.longValue() * 1000));
System.out.println(record.getRecordNumber()
+ " Event ID: " + (short) record.getEventId()
+ ", Event Type: " + record.getType()
+ ", Event Time: " + generatedTime
+ ": Event Category: " + record1.EventCategory.toString()
+ ", Event Source: " + record.getSource()
+ ", Event Description: " + data.toString());
}
}
结果:
4 实现原理
首先查看类Advapi32.java
可以看到该实例加载了一个本地动态链接库(Advapi32.dll),这个文件是Windows系统下自带的(没有的话还请自行下载)。
可以看到,这个接口实现了该链接库对应的OpenEventLog方法,第一个参数ServerName(一般置null),第二个参数代表日志类型(Application:应用程序;Security:安全;Setup;System:系统),其中安全日志需要将IDEA以管理员身份运行方可成功。
这就是利用JNA读取系统日志文件的核心部分。
不足的是,该方法仅能读取本机的日志文件,对于从别的电脑导出的日志文件的读取,暂时还无法实现(指定文件绝对路径来读取或是以文件类型做参数来读取),且需要人为指定系统日志的类型(Setup类型还无法读取),后续将继续完善