R
Robert
Some TODO's in there which I will fix in 12-16 hours. Beer time here on the beach..
Also, I have only used this via the test case. I have not plugged it into a BinaryReader
yet. There may be some impedance mismatches...
145 lines for the class, 170 with the test case.
3 hours work. so about 1 line per minute, including the blank ones
Last, there is at least one bug..
Happy file reading to all!
Imports System.IO
Imports System.Collections.Generic
Friend Class ForwardOnlyFileReader : Inherits Stream
Friend Class BufferChunk
Private mChunk() As Byte
Private mStartingPosition As Long
Friend ReadOnly Property StartingPosition() As Long
Get
Return mStartingPosition
End Get
End Property
Friend ReadOnly Property LastPosition() As Long
Get
Return mStartingPosition + mChunk.Length
End Get
End Property
Friend Sub New(ByVal StartingPosition As Long, ByRef Chunk() As Byte)
If Chunk.Count = 0 Then Throw New System.ArgumentNullException("Bufferchunk.Read - Chunk is Null.")
mStartingPosition = StartingPosition
mChunk = Chunk
End Sub
Friend Function Read(ByVal ChunkOffset As Integer, ByVal Buffer() As Byte, ByVal BufferOffset As Integer, ByVal
DesiredBytes As Integer) As Integer
DesiredBytes = Math.Min(DesiredBytes, mChunk.Count - ChunkOffset) ' take what we can get..
Array.ConstrainedCopy(mChunk, ChunkOffset, Buffer, BufferOffset, DesiredBytes)
Return DesiredBytes
End Function
End Class
Private mBufferChunks As New List(Of BufferChunk)
Private mChunkSize As Integer
Private mLength As Long
Private mPosition As Long
Public Sub New(ByVal FileStream As FileStream, ByVal ChunkSize As Integer)
If FileStream Is Nothing Then Throw New System.ArgumentNullException("FileStream is null.")
If Not FileStream.CanRead Then Throw New System.NotSupportedException("The stream does not support reading.")
mChunkSize = ChunkSize
mLength = FileStream.Length
Dim aBufferChunk As BufferChunk
Do Until FileStream.Position = mLength
Dim PositionBeforeRead As Long = FileStream.Position
Dim Buffer(CInt(Math.Min(ChunkSize - 1, mLength - FileStream.Position - 1))) As Byte
Dim Bytes As Integer = FileStream.Read(Buffer, 0, Buffer.Count)
aBufferChunk = New BufferChunk(PositionBeforeRead, Buffer)
mBufferChunks.Add(aBufferChunk)
Loop
FileStream.Close()
FileStream.Dispose()
End Sub
'TODO another constructor with AutoResetEvent
Public Overrides Function Read(ByVal Buffer() As Byte, ByVal BufferOffset As Integer, ByVal Count As Integer) As
Integer
Dim BytesRead As Integer
Dim BytesRemaining As Integer = Count
Dim ChunkOffset As Integer
If BufferOffset < 0 Then Throw New System.ArgumentOutOfRangeException("Bufferchunk.Read - BufferOffset is < 0.")
If Count < 0 Then Throw New System.ArgumentOutOfRangeException("FOFR.Read - count is < 0.")
'TODO - implement System.ArgumentException: The sum of offset and count is larger than the buffer length.
'TODO - implement System.ArgumentNullException: buffer is null.
'cant happen with mem - System.IO.IOException: An I/O error occurs. cant happen with mem
'TODO - implement System.ObjectDisposedException: Methods were called after the stream was closed.
Do
Do While mBufferChunks.Count > 0
If mPosition >= mBufferChunks.Item(0).LastPosition Then
mBufferChunks.RemoveAt(0)
Else
Exit Do ' we have the right chunk.
End If
Loop
If mBufferChunks.Count = 0 Then Return BytesRead
ChunkOffset = CInt(mPosition - mBufferChunks(0).StartingPosition)
BytesRead = mBufferChunks(0).Read(ChunkOffset, Buffer, BufferOffset, BytesRemaining)
BufferOffset = BufferOffset + BytesRead
BytesRemaining = BytesRemaining - BytesRead
mPosition = mPosition + BytesRead
Loop Until (BytesRemaining = 0) Or (mPosition = mLength) ' filled the buffer, or eof
Return BytesRead
End Function
#Region "Properties"
Public Overrides ReadOnly Property Length() As Long
Get
Return mLength
End Get
End Property
Public Overrides Property Position() As Long
Get
Return mPosition
End Get
Set(ByVal value As Long)
mPosition = value ' BufferChunks will be lost..
End Set
End Property
#Region "Unused Properties"
Public Overrides ReadOnly Property CanRead() As Boolean
Get
Return True
End Get
End Property
Public Overrides ReadOnly Property CanSeek() As Boolean
Get
Return False
End Get
End Property
Public Overrides ReadOnly Property CanWrite() As Boolean
Get
Return False
End Get
End Property
Public Overrides Sub Flush()
Throw New NotSupportedException("ForwardOnlyMemoryStreamReader does not support Flush.")
End Sub
Public Overrides Function Seek(ByVal offset As Long, ByVal origin As System.IO.SeekOrigin) As Long
Throw New System.NotSupportedException("ForwardOnlyMemoryStreamReader does not support Seek.")
End Function
Public Overrides Sub SetLength(ByVal value As Long)
Throw New NotSupportedException("ForwardOnlyMemoryStreamReader does not support SetLength.")
End Sub
Public Overrides Sub Write(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer)
Throw New NotSupportedException("ForwardOnlyMemoryStreamReader does not support Write.")
End Sub
#End Region
#End Region
End Class
Friend Class FOFiRTest
Friend Function Test() As Boolean
Dim i As Integer
Dim ActualText As String = File.ReadAllText("c:\ForwardOnlyFileReaderTest.txt")
' Create a file with notepad.. 'ActualText = "abcdefghijklmnopqrstuvwxyz0123456789"
Dim encoding As System.Text.Encoding = System.Text.Encoding.ASCII
For i = 1 To 64
Dim s As String = ""
Dim TestFileStream As New FileStream("c:\ForwardOnlyFileReaderTest.txt", FileMode.Open)
Dim FOFir As New ForwardOnlyFileReader(TestFileStream, i)
Dim Bytes(5) As Byte ' TODO - FIX BUG Put another for loop inside For i, and vary the buffer size. 3 works,
5 fails.
Do While FOFir.Read(Bytes, 0, 3) > 0 ' 3 bytes
s = s & encoding.GetString(Bytes)
Loop
If s.Length <> ActualText.Length Then
If s <> ActualText Then Return False
End If
Next
Return True
End Function
End Class
Also, I have only used this via the test case. I have not plugged it into a BinaryReader
yet. There may be some impedance mismatches...
145 lines for the class, 170 with the test case.
3 hours work. so about 1 line per minute, including the blank ones
Last, there is at least one bug..
Happy file reading to all!
Imports System.IO
Imports System.Collections.Generic
Friend Class ForwardOnlyFileReader : Inherits Stream
Friend Class BufferChunk
Private mChunk() As Byte
Private mStartingPosition As Long
Friend ReadOnly Property StartingPosition() As Long
Get
Return mStartingPosition
End Get
End Property
Friend ReadOnly Property LastPosition() As Long
Get
Return mStartingPosition + mChunk.Length
End Get
End Property
Friend Sub New(ByVal StartingPosition As Long, ByRef Chunk() As Byte)
If Chunk.Count = 0 Then Throw New System.ArgumentNullException("Bufferchunk.Read - Chunk is Null.")
mStartingPosition = StartingPosition
mChunk = Chunk
End Sub
Friend Function Read(ByVal ChunkOffset As Integer, ByVal Buffer() As Byte, ByVal BufferOffset As Integer, ByVal
DesiredBytes As Integer) As Integer
DesiredBytes = Math.Min(DesiredBytes, mChunk.Count - ChunkOffset) ' take what we can get..
Array.ConstrainedCopy(mChunk, ChunkOffset, Buffer, BufferOffset, DesiredBytes)
Return DesiredBytes
End Function
End Class
Private mBufferChunks As New List(Of BufferChunk)
Private mChunkSize As Integer
Private mLength As Long
Private mPosition As Long
Public Sub New(ByVal FileStream As FileStream, ByVal ChunkSize As Integer)
If FileStream Is Nothing Then Throw New System.ArgumentNullException("FileStream is null.")
If Not FileStream.CanRead Then Throw New System.NotSupportedException("The stream does not support reading.")
mChunkSize = ChunkSize
mLength = FileStream.Length
Dim aBufferChunk As BufferChunk
Do Until FileStream.Position = mLength
Dim PositionBeforeRead As Long = FileStream.Position
Dim Buffer(CInt(Math.Min(ChunkSize - 1, mLength - FileStream.Position - 1))) As Byte
Dim Bytes As Integer = FileStream.Read(Buffer, 0, Buffer.Count)
aBufferChunk = New BufferChunk(PositionBeforeRead, Buffer)
mBufferChunks.Add(aBufferChunk)
Loop
FileStream.Close()
FileStream.Dispose()
End Sub
'TODO another constructor with AutoResetEvent
Public Overrides Function Read(ByVal Buffer() As Byte, ByVal BufferOffset As Integer, ByVal Count As Integer) As
Integer
Dim BytesRead As Integer
Dim BytesRemaining As Integer = Count
Dim ChunkOffset As Integer
If BufferOffset < 0 Then Throw New System.ArgumentOutOfRangeException("Bufferchunk.Read - BufferOffset is < 0.")
If Count < 0 Then Throw New System.ArgumentOutOfRangeException("FOFR.Read - count is < 0.")
'TODO - implement System.ArgumentException: The sum of offset and count is larger than the buffer length.
'TODO - implement System.ArgumentNullException: buffer is null.
'cant happen with mem - System.IO.IOException: An I/O error occurs. cant happen with mem
'TODO - implement System.ObjectDisposedException: Methods were called after the stream was closed.
Do
Do While mBufferChunks.Count > 0
If mPosition >= mBufferChunks.Item(0).LastPosition Then
mBufferChunks.RemoveAt(0)
Else
Exit Do ' we have the right chunk.
End If
Loop
If mBufferChunks.Count = 0 Then Return BytesRead
ChunkOffset = CInt(mPosition - mBufferChunks(0).StartingPosition)
BytesRead = mBufferChunks(0).Read(ChunkOffset, Buffer, BufferOffset, BytesRemaining)
BufferOffset = BufferOffset + BytesRead
BytesRemaining = BytesRemaining - BytesRead
mPosition = mPosition + BytesRead
Loop Until (BytesRemaining = 0) Or (mPosition = mLength) ' filled the buffer, or eof
Return BytesRead
End Function
#Region "Properties"
Public Overrides ReadOnly Property Length() As Long
Get
Return mLength
End Get
End Property
Public Overrides Property Position() As Long
Get
Return mPosition
End Get
Set(ByVal value As Long)
mPosition = value ' BufferChunks will be lost..
End Set
End Property
#Region "Unused Properties"
Public Overrides ReadOnly Property CanRead() As Boolean
Get
Return True
End Get
End Property
Public Overrides ReadOnly Property CanSeek() As Boolean
Get
Return False
End Get
End Property
Public Overrides ReadOnly Property CanWrite() As Boolean
Get
Return False
End Get
End Property
Public Overrides Sub Flush()
Throw New NotSupportedException("ForwardOnlyMemoryStreamReader does not support Flush.")
End Sub
Public Overrides Function Seek(ByVal offset As Long, ByVal origin As System.IO.SeekOrigin) As Long
Throw New System.NotSupportedException("ForwardOnlyMemoryStreamReader does not support Seek.")
End Function
Public Overrides Sub SetLength(ByVal value As Long)
Throw New NotSupportedException("ForwardOnlyMemoryStreamReader does not support SetLength.")
End Sub
Public Overrides Sub Write(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer)
Throw New NotSupportedException("ForwardOnlyMemoryStreamReader does not support Write.")
End Sub
#End Region
#End Region
End Class
Friend Class FOFiRTest
Friend Function Test() As Boolean
Dim i As Integer
Dim ActualText As String = File.ReadAllText("c:\ForwardOnlyFileReaderTest.txt")
' Create a file with notepad.. 'ActualText = "abcdefghijklmnopqrstuvwxyz0123456789"
Dim encoding As System.Text.Encoding = System.Text.Encoding.ASCII
For i = 1 To 64
Dim s As String = ""
Dim TestFileStream As New FileStream("c:\ForwardOnlyFileReaderTest.txt", FileMode.Open)
Dim FOFir As New ForwardOnlyFileReader(TestFileStream, i)
Dim Bytes(5) As Byte ' TODO - FIX BUG Put another for loop inside For i, and vary the buffer size. 3 works,
5 fails.
Do While FOFir.Read(Bytes, 0, 3) > 0 ' 3 bytes
s = s & encoding.GetString(Bytes)
Loop
If s.Length <> ActualText.Length Then
If s <> ActualText Then Return False
End If
Next
Return True
End Function
End Class