Windows日志文件具有以下特点:
1、系统启动后,系统日志处于打开状态,它是不能直接修改的,但是可以查询;如若想修改必须处于另一操作系统中修改,或者将其拷出修改,再修改注册表指向修改后的日志文件。
2、系统日志具有顺序存储的结构,包括头记录(48字节),记录项(前4字节为记录长度,其后为记录内容,其中内容为Windows特定长度的二进制信息,由Windows日志程序处理后,信息才连贯显示,否则只是记录的各个字段罗列),尾记录(40字节),后边为填充的00项字节,无意义。
编程中遇到的问题:
1、记录项过多时,不能用checkedlistbox或listbox等控件存储数据,否则,系统在加入数据记录到列表框时,速度越来越慢。所以我改用了DataTable,这个确实较上一个快。
2、Windows API 日志存储数据结构。
typedef struct _EVENTLOGRECORD {
DWORD Length;
DWORD Reserved;
DWORD RecordNumber;
DWORD TimeGenerated;
DWORD TimeWritten;
DWORD EventID;
WORD EventType;
WORD NumStrings;
WORD EventCategory;
WORD ReservedFlags;
DWORD ClosingRecordNumber;
DWORD StringOffset;
DWORD UserSidLength;
DWORD UserSidOffset;
DWORD DataLength;
DWORD DataOffset;
} EVENTLOGRECORD, *PEVENTLOGRECORD;
3、EventID代表不同事件类型,如6008为意外关机
4、EventType有几种不同意义,分别为1 错误\2 警告\4 信息\8 成功审核\10h 失败审核;
5、TimeWritten从1970-1-1 00:00:00开始的秒数,但是中国为第八时区(北京时间)所以开始时间为1970-1-1 08:00:00(我猜的,因为加上8个小时就和日志的时间对上了)
6、下面是我编写的一段用来读取日志记录信息的程序(VB.Net)
Public Function get_info(ByVal fieldname As String, ByVal i As Integer) As Object
Dim disp_str, rec_str As String
Dim byte_str() As String
disp_str = ""
rec_str = ""
TextBox1.Text = ""
'读取记录信息
'1、记录长度;
Dim rec_leng As Integer
'2、保留;
'3、记录号;
Dim rec_num As Integer
rec_num = 0
'4、消逝时间;
Dim time_gene As System.Int32
time_gene = 0
'5、写入时间;
Dim time_writ As System.Int32
'6、事件编号;
Dim event_id As System.Int32
'7、事件类型;
Dim event_type As Integer
'8、NumString;
Dim msg_count As Integer
'9、EventCategory;
Dim eventG As System.Int32
'10、ReservedFlags;
'11、ClosingRecordNumber;
Dim CloseRecNum As System.Int64
'12、StringOffset;
Dim stroffset As System.Int32
'13、UserSidLength;
Dim UserSidLength As System.Int64
'14、UserSidOffset;
Dim UserSidOffset As System.Int64
'15、DataLength;
Dim DataLen As System.Int64
'16、DataOffset;
Dim DataOff As System.Int64
'17 信息来源 '两项内容计算推得,不用定义
'18 信息内容
'当前item的二进制内容
rec_str = filetable.Rows(i)(1).ToString
'将二进制序列重新编排成字节数组
byte_str = Split(rec_str, ",")
'1、提取记录长度
Dim byte_count As System.Int32
rec_leng = 0
Select Case fieldname
Case "记录长度"
For byte_count = 0 To 3
rec_leng = rec_leng + Convert.ToInt32(byte_str(byte_count)) * (256 ^ byte_count)
Next
get_info = rec_leng.ToString
Case "记录号"
For byte_count = 8 To 11
rec_num = rec_num + Convert.ToInt32(byte_str(byte_count)) * (256 ^ (byte_count - 8))
Next
get_info = rec_num.ToString
Case "消逝时间"
For byte_count = 12 To 15
time_gene = time_gene + Convert.ToInt32(byte_str(byte_count)) * (256 ^ (byte_count - 12))
Next
Dim NewDate As DateTime = DateAdd("s", time_gene, "1970-1-1 08:00:00")
get_info = NewDate.ToString
Case "写入时间"
For byte_count = 16 To 19
time_writ = time_writ + Convert.ToInt32(byte_str(byte_count)) * (256 ^ (byte_count - 16))
Next
Dim NewDate As DateTime = DateAdd("s", time_writ, "1970-1-1 08:00:00")
get_info = NewDate.ToString
Case "事件编号"
For byte_count = 20 To 21
event_id = event_id + Convert.ToInt32(byte_str(byte_count)) * (256 ^ (byte_count - 20))
Next
get_info = event_id.ToString
Case "事件类型"
'Dim str_type As String
For byte_count = 24 To 25
event_type = event_type + Convert.ToInt32(byte_str(byte_count)) * (256 ^ (byte_count - 24))
Next
'Select Case event_type
'Case 1
' str_type = " 错误"
'Case 2
' str_type = " 警告"
'Case 4
' str_type = " 信息"
'Case 8
' str_type = " 成功审核"
'Case 16
' str_type = " 失败审核"
'Case Else
' str_type = event_type.ToString
'End Select
'disp_info_new = str_type.ToString
get_info = event_type.ToString
Case "事件信息量"
msg_count = 0
For byte_count = 26 To 27
msg_count = msg_count + Convert.ToInt32(byte_str(byte_count)) * (256 ^ (byte_count - 26))
Next
get_info = msg_count.ToString
Case "EventGategory"
eventG = 0
For byte_count = 28 To 29
eventG = eventG + Convert.ToInt32(byte_str(byte_count)) * (256 ^ (byte_count - 28))
Next
get_info = eventG.ToString
Case "ClosingRecordNumber"
CloseRecNum = 0
For byte_count = 32 To 35
CloseRecNum = CloseRecNum + Convert.ToInt32(byte_str(byte_count)) * (256 ^ (byte_count - 32))
Next
get_info = CloseRecNum.ToString
Case "StringOffset"
stroffset = 0
For byte_count = 36 To 39
stroffset = stroffset + Convert.ToInt32(byte_str(byte_count)) * (256 ^ (byte_count - 36))
Next
get_info = stroffset.ToString
Case "UserSidLength"
UserSidLength = 0
For byte_count = 40 To 43
UserSidLength = UserSidLength + Convert.ToInt64(byte_str(byte_count)) * (256 ^ (byte_count - 40))
Next
get_info = UserSidLength.ToString
Case "UserSidOffset"
UserSidOffset = 0
For byte_count = 44 To 47
UserSidOffset = UserSidOffset + Convert.ToInt64(byte_str(byte_count)) * (256 ^ (byte_count - 44))
Next
get_info = UserSidOffset.ToString
Case "DataLen"
DataLen = 0
For byte_count = 48 To 51
DataLen = DataLen + Convert.ToInt64(byte_str(byte_count)) * (256 ^ (byte_count - 48))
Next
get_info = DataLen.ToString
Case "DataOffset"
DataOff = 0
For byte_count = 52 To 55
DataOff = DataOff + Convert.ToInt64(byte_str(byte_count)) * (256 ^ (byte_count - 52))
Next
get_info = DataOff.ToString
Case "信息来源"
rec_leng = byte_str.Length
Dim SourceInfo As String
SourceInfo = ""
byte_count = 56
While byte_count < rec_leng
If byte_str(byte_count) = "0" And byte_str(byte_count + 1) = "0" Then
byte_count = byte_count + 2
Exit While
End If
SourceInfo = SourceInfo + word_str(byte_str(byte_count), byte_str(byte_count + 1))
byte_count = byte_count + 2
End While
get_info = SourceInfo.ToString
Case "计算机名"
Dim HostName As String
HostName = ""
rec_leng = byte_str.Length
byte_count = 56
While byte_count < rec_leng
If byte_str(byte_count) = "0" And byte_str(byte_count + 1) = "0" Then
byte_count = byte_count + 2
Exit While
End If
byte_count = byte_count + 2
End While
While byte_count < rec_leng
If byte_str(byte_count) = "0" And byte_str(byte_count + 1) = "0" Then
byte_count = byte_count + 2
Exit While
End If
HostName = HostName + word_str(byte_str(byte_count), byte_str(byte_count + 1))
byte_count = byte_count + 2
End While
get_info = HostName
Case "记录信息"
Dim MessageContent As String
stroffset = 0
MessageContent = ""
For byte_count = 36 To 39
stroffset = stroffset + Convert.ToInt32(byte_str(byte_count)) * (256 ^ (byte_count - 36))
Next
byte_count = stroffset
While byte_count < rec_leng - 4
If (byte_str(byte_count) = "0") And (byte_str(byte_count + 1) = "0") And (byte_str(byte_count + 2) = "0") And (byte_str(byte_count + 3) = "0") Then
Exit While
End If
If (byte_str(byte_count) = "0") And (byte_str(byte_count + 1) = "0") Then
MessageContent = MessageContent + "-00-"
Else
MessageContent = MessageContent + word_str(byte_str(byte_count), byte_str(byte_count + 1))
End If
byte_count = byte_count + 2
End While
get_info = MessageContent
Case Else
get_info = "无此内容项"
End Select
End Function
Public Sub AddLogItem(ByVal logfilename As String, ByVal dgv As DataGridView)
'********************************
Dim filerow As DataRow
'********************************
Const rec_len = 8
Const mem_bs = 524288
Dim flag_string As String
Dim mem_byte(mem_bs) As Byte
Dim mem_cnt, mem_length As Integer '当前记录块的数量-1 ,记录块实际长度
Dim cur_pos, old_pos As System.Int32 '当前记录文件的指针
Dim elsp_time As DateTime
elsp_time = Now
Dim temp_buffer(1) As Byte
Dim temp_str As String
Dim len_buffer(rec_len) As Byte
Dim content_len As System.Int32
Dim rec_log As String
Dim rec_count As System.Int32
Dim count_total As System.Int32
mem_cnt = 0
old_pos = 0
rec_count = 0
count_total = 0
temp_str = ""
If logfilename.Length = 0 Then
MessageBox.Show("Error, logfile is empty!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Exit Sub
End If
logfile = New FileInfo(logfilename)
Try
logfilestream = New FileStream(logfilename, FileMode.OpenOrCreate, FileAccess.ReadWrite)
While cur_pos < logfilestream.Length
'读入1MB的文件内容
If mem_cnt = 0 Then
mem_length = logfilestream.Read(mem_byte, 0, mem_bs)
Else
logfilestream.Seek(cur_pos, SeekOrigin.Begin)
mem_length = logfilestream.Read(mem_byte, 0, mem_bs)
End If
'时间标志
elsp_time = Now
TextBox1.Text = TextBox1.Text + elsp_time.ToString + vbCrLf
TextBox1.Refresh()
'开始处理这1MB的内容
Do While count_total < mem_length
copybyte(len_buffer, mem_byte, count_total, rec_len)
'产生记录的特征串(第5-8字节)
flag_string = len_buffer(4).ToString + len_buffer(5).ToString + len_buffer(6).ToString + len_buffer(7).ToString
If flag_string = "7610276101" Then
temp_str = ""
'计算每条记录长度
content_len = Convert.ToInt32(len_buffer(0)) + Convert.ToInt32(len_buffer(1)) * 256 + Convert.ToInt32(len_buffer(2)) * 256 * 256 + Convert.ToInt32(len_buffer(3)) * 256 * 256 * 256
'对于不能完全从缓冲区中读取的数据转到下一个数据段处理
If (count_total + content_len > mem_bs) Then
cur_pos = count_total + old_pos
old_pos = old_pos + count_total
count_total = 0
mem_cnt = mem_cnt + 1
Exit Do
End If
Dim count As System.Int32
count = 0
rec_log = ""
'把读出的记录存入字符串数组
rec_log = mem_byte(count_total).ToString
For count = count_total + 1 To count_total + content_len
rec_log = rec_log + "," + mem_byte(count).ToString
Next
count_total = count_total + content_len
'如果为第一条记录则不加入列表框
If rec_count > 0 Then
filerow = filetable.NewRow
filerow.Item(0) = rec_count.ToString
filerow.Item(1) = rec_log
filetable.Rows.Add(filerow)
filerow = Nothing
End If
rec_count = rec_count + 1
ToolStripProgressBar1.Value = ToolStripProgressBar1.Value + content_len
'如果缓冲区中的数据正好处理完毕,则读取下一个数据段
If count_total = mem_length Then
cur_pos = count_total + old_pos
old_pos = old_pos + count_total
count_total = 0
mem_cnt = mem_cnt + 1
Exit Do
End If
Else
'后边没有记录时,以0填充,数据不再有意义,即数据已读出,可退出循环!
If flag_string = "17171717" Then
ToolStripProgressBar1.Value = ToolStripProgressBar1.Maximum
Exit While
End If
'绕过头记录的00填充字节
copybyte(temp_buffer, mem_byte, count_total, 1)
temp_str = temp_str + temp_buffer.ToString
ToolStripProgressBar1.Value = ToolStripProgressBar1.Value + 1
count_total = count_total + 1
End If
Loop
End While
logfilestream.Close()
dgv.DataSource = filetable
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
ToolStripStatusLabel1.Text = filetable.Rows.Count.ToString() + " records is loaded!" '+ " checkedlistbox1:" + CheckedListBox1.Items.Count.ToString
End Sub
Public Sub copybyte(ByVal desc() As Byte, ByVal source() As Byte, ByVal offset As Integer, ByVal len As Integer)
'本函数属于无保护的过程,请慎重使用
Dim i, j As Integer
For i = offset To offset + len - 1
desc(j) = source(i)
j = j + 1
Next
End Sub