mirror of
https://github.com/staxrip/staxrip.git
synced 2026-10-19 15:20:36 +08:00
145 lines
4.1 KiB
VB.net
145 lines
4.1 KiB
VB.net
|
|
Imports System.Text
|
|
Imports System.Threading
|
|
|
|
Imports VB6 = Microsoft.VisualBasic
|
|
|
|
Public Class AsyncStreamReader
|
|
Implements IDisposable
|
|
|
|
Const DefaultBufferSize As Integer = 1024
|
|
Private Stream As Stream
|
|
Private Decoder As Decoder
|
|
Private ByteBuffer As Byte()
|
|
Private CharBuffer As Char()
|
|
Private MaxCharsPerBuffer As Integer
|
|
Private CallBack As Action(Of String)
|
|
Private EofEvent As New ManualResetEvent(False)
|
|
Private Queue As New Queue(Of String)
|
|
Private SB As StringBuilder
|
|
Private LastCarriageReturn As Boolean
|
|
Private CurrentLinePos As Integer
|
|
|
|
Sub New(stream As Stream, callback As Action(Of String), encoding As Encoding)
|
|
Me.Stream = stream
|
|
Me.CallBack = callback
|
|
Decoder = encoding.GetDecoder()
|
|
ByteBuffer = New Byte(DefaultBufferSize - 1) {}
|
|
MaxCharsPerBuffer = encoding.GetMaxCharCount(DefaultBufferSize)
|
|
CharBuffer = New Char(MaxCharsPerBuffer - 1) {}
|
|
End Sub
|
|
|
|
Sub Dispose() Implements IDisposable.Dispose
|
|
If Not Stream Is Nothing Then
|
|
Stream.Close()
|
|
EofEvent.Close()
|
|
Stream = Nothing
|
|
End If
|
|
End Sub
|
|
|
|
Sub BeginReadLine()
|
|
SB = New StringBuilder(DefaultBufferSize)
|
|
Stream.BeginRead(ByteBuffer, 0, ByteBuffer.Length, New AsyncCallback(AddressOf ReadBuffer), Nothing)
|
|
End Sub
|
|
|
|
Sub ReadBuffer(ar As IAsyncResult)
|
|
Dim byteLen As Integer
|
|
|
|
Try
|
|
byteLen = Stream.EndRead(ar)
|
|
Catch
|
|
byteLen = 0
|
|
End Try
|
|
|
|
If byteLen = 0 Then
|
|
SyncLock Queue
|
|
If SB.Length <> 0 Then
|
|
Queue.Enqueue(SB.ToString())
|
|
SB.Length = 0
|
|
End If
|
|
|
|
Queue.Enqueue(Nothing)
|
|
End SyncLock
|
|
|
|
FlushMessageQueue()
|
|
EofEvent.Set()
|
|
Else
|
|
Dim charLen = Decoder.GetChars(ByteBuffer, 0, byteLen, CharBuffer, 0)
|
|
SB.Append(CharBuffer, 0, charLen)
|
|
GetLinesFromStringBuilder()
|
|
Stream.BeginRead(ByteBuffer, 0, ByteBuffer.Length, New AsyncCallback(AddressOf ReadBuffer), Nothing)
|
|
End If
|
|
End Sub
|
|
|
|
Sub GetLinesFromStringBuilder()
|
|
Dim currentIndex = CurrentLinePos
|
|
Dim lineStart As Integer
|
|
Dim len = SB.Length
|
|
Dim BackSpace = VB6.Chr(8)
|
|
Dim LineFeet = VB6.Chr(10)
|
|
Dim CarriageReturn = VB6.Chr(13)
|
|
|
|
If LastCarriageReturn AndAlso len > 0 AndAlso SB(0) = LineFeet Then
|
|
currentIndex = 1
|
|
lineStart = 1
|
|
LastCarriageReturn = False
|
|
End If
|
|
|
|
While currentIndex < len
|
|
Dim ch = SB(currentIndex)
|
|
|
|
If ch = CarriageReturn OrElse ch = LineFeet OrElse ch = BackSpace Then
|
|
Dim str = SB.ToString(lineStart, currentIndex - lineStart)
|
|
lineStart = currentIndex + 1
|
|
|
|
If ch = CarriageReturn AndAlso lineStart < len AndAlso SB(lineStart) = LineFeet Then
|
|
lineStart += 1
|
|
currentIndex += 1
|
|
End If
|
|
|
|
SyncLock Queue
|
|
Queue.Enqueue(str)
|
|
End SyncLock
|
|
End If
|
|
|
|
currentIndex += 1
|
|
End While
|
|
|
|
If len > 0 AndAlso SB(len - 1) = CarriageReturn Then
|
|
LastCarriageReturn = True
|
|
End If
|
|
|
|
If lineStart < len Then
|
|
If lineStart = 0 Then
|
|
CurrentLinePos = currentIndex
|
|
Else
|
|
SB.Remove(0, lineStart)
|
|
CurrentLinePos = 0
|
|
End If
|
|
Else
|
|
SB.Length = 0
|
|
CurrentLinePos = 0
|
|
End If
|
|
|
|
FlushMessageQueue()
|
|
End Sub
|
|
|
|
Sub FlushMessageQueue()
|
|
While True
|
|
If Queue.Count > 0 Then
|
|
SyncLock Queue
|
|
If Queue.Count > 0 Then
|
|
CallBack(Queue.Dequeue())
|
|
End If
|
|
End SyncLock
|
|
Else
|
|
Exit While
|
|
End If
|
|
End While
|
|
End Sub
|
|
|
|
Sub WaitUtilEOF()
|
|
EofEvent.WaitOne()
|
|
End Sub
|
|
End Class
|