Die Community zu .NET und Classic VB.
Menü

VB.NET-Tipp 0101: Stream-Konzepte

 von 

Beschreibung

Lese- und Schreibvorgänge aller Art werden unter Visual Basic .NET vorzugsweise mittels Streams verwaltet. Je nach Bedarf gibt es deren sehr viele, drei grundlegende Konzepte teilen sie jedoch miteinander:
1) Die Daten können portionsweise gelesen beziehungsweise geschrieben werden. Das ermöglicht unendlich große Datenmengen zu bewegen, ohne einen entsprechend unendlich großen Zwischenspeicher vorhalten zu müssen. Essentiell sind daher die gezeigte(n) Schleife(n) zum gepufferten Kopieren eines Streams in einen anderen.
2) Streams verschiedenster Art können aufeinander aufgesetzt werden, wodurch die Ausgabe des einen Streams direkt zur Eingabe des anderen wird. Diese Eigenschaft ist wichtig zum Bau von Konvertern - es können viele Verarbeitungsschritte hintereinander geschaltet werden (s. Pipes and Filters ).
3) Zu erwähnen wären noch die verschiedenen Reader und Writer, die ebenfalls aufgesetzt werden können, und quasi als "Adapter" zur letztendlichen Datenverarbeitung funktionieren.

Die Kompatiblität der Streams erleichtert es sehr wiederverwendbaren Code zu schreiben: Würde man wie in diesem Beispiel statt der Filestreams NetworkStreams anschließen, so könnte man dieselben Daten ebensogut über das Internet verschicken.

Schwierigkeitsgrad:

Schwierigkeitsgrad 1

Framework-Version(en):

.NET Framework 2.0, .NET Framework 3.0, .NET Framework 3.5

.NET-Version(en):

Visual Basic 2008

Download:

Download des Beispielprojektes [25,94 KB]

' Dieser Quellcode stammt von http://www.activevb.de
' und kann frei verwendet werden. Für eventuelle Schäden
' wird nicht gehaftet.

' Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
' Ansonsten viel Spaß und Erfolg mit diesem Source!

' Projektversion:   Visual Studio 2008
' Option Strict:    An
' Option Infer:     An
'
' Referenzen: 
'  - System
'  - System.Core
'  - System.Data
'  - System.Data.DataSetExtensions
'  - System.Deployment
'  - System.Drawing
'  - System.Windows.Forms
'  - System.Xml
'
' Imports: 
'  - Microsoft.VisualBasic
'  - Microsoft.VisualBasic.ControlChars
'  - System
'  - System.Collections.Generic
'  - System.Data
'  - System.Diagnostics
'  - System.Linq
'  - System.Windows.Forms
'

' ##############################################################################
' ################################# Form1.vb ###################################
' ##############################################################################
Imports System.IO

Public Class Form1

    Private Sub MenuItem_Click(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles _
        btZipWordDoc.Click, btUnzipWordDoc.Click, btShowDocuments.Click, _
        btStoreControls.Click, btRestoreControls.Click

        Select Case True
            Case sender Is btZipWordDoc
                modGZip.Zip("Test.doc", "Test.gzip")

            Case sender Is btUnzipWordDoc
                modGZip.UnZip("Test.gzip", "Test2.doc")

            Case sender Is btShowDocuments
                Process.Start("Test.doc")
                Process.Start("Test2.doc")

            Case sender Is btStoreControls
                ' Zum Schreiben einen (Binary-)Writer auf einen Stream aufsetzen
                Using fs As New FileStream("data.dat", FileMode.Create), _
                    writer As New BinaryWriter(fs)

                    writer.Write(CheckBox1.Checked)
                    writer.Write(TextBox1.Text)
                    writer.Write(NumericUpDown1.Value)
                    writer.Write(DateTimePicker1.Value.Ticks)
                End Using

            Case sender Is btRestoreControls
                ' Zum Lesen einen (Binary-)Reader auf einen Stream aufsetzen
                Using fs As New FileStream("data.dat", FileMode.Open), _
                    reader As New BinaryReader(fs)

                    CheckBox1.Checked = reader.ReadBoolean
                    TextBox1.Text = reader.ReadString
                    NumericUpDown1.Value = reader.ReadDecimal
                    DateTimePicker1.Value = Date.FromBinary(reader.ReadInt64)
                End Using
        End Select

        My.Computer.Audio.PlaySystemSound(Media.SystemSounds.Asterisk)
    End Sub
End Class
' ##############################################################################
' ################################ modGZip.vb ##################################
' ##############################################################################
Imports System.IO
Imports System.IO.Compression

Public Module modGZip

    Public Sub Zip(ByVal src As String, ByVal dest As String)
        ' Durch Zwischenschalten des GZipStreams wird aus einem Kopier-Vorgang 
        '  eine GZip-Konvertierung (die komprimierte Datei ist nicht 
        '  Zip-kompatibel)

        Using readStream As New FileStream(src, FileMode.Open), _
            writeStream As New FileStream(dest, FileMode.Create), _
            zipper As New GZipStream(writeStream, CompressionMode.Compress)

            ' (Puffer zum Testen absurd klein gewählt)
            Dim bufSize As Integer = Byte.MaxValue
            Dim buf(bufSize - 1) As Byte

            ' Standard-Kopier-Schleife für Streams mit festgelegtem Ende
            Do
                bufSize = readStream.Read(buf, 0, bufSize)
                zipper.Write(buf, 0, bufSize)
                ' Schleife endet, wenn Puffer nicht ganz befüllt wurde
            Loop Until bufSize < buf.Length
        End Using
    End Sub

    Public Sub UnZip(ByVal src As String, ByVal dest As String)
        ' Rück-Konvertierung. Beachte, daß hier der GZipStream auf dem Read-
        ' Stream  aufsitzt, und mit CompressionMode.Decompress erstellt ist.
        Using readStream As New FileStream(src, FileMode.Open), _
            unZipper As New GZipStream(readStream, _
                CompressionMode.Decompress), _
            writeStream As New FileStream(dest, FileMode.Create)

            ' Verwendung der in die Extension-Methode ausgelagerten Kopier-
            '  Schleife
            unZipper.WriteTo(writeStream)
        End Using
    End Sub

End Module

' ##############################################################################
' ################################ StreamX.vb ##################################
' ##############################################################################
Imports System.Runtime.CompilerServices
Imports System.IO

Public Module StreamX

    ''' <summary> Kopiert von einem Stream in einen Anderen </summary>
    ''' <remarks> 
    '''  Es gibt Streams ohne festgelegtes Ende (z.B. NetworkStream).
    '''  In solchem Fall **muss** 'count' angegeben werden.
    ''' </remarks>
    <Extension()> _
    Public Sub WriteTo( _
        ByVal readStream As Stream, _
        ByVal writeStream As Stream, _
        Optional ByVal count As Long = -1, _
        Optional ByVal bufSize As Integer = Short.MaxValue)

        Dim buf(bufSize - 1) As Byte
        If count < 0 AndAlso readStream.CanSeek Then
            count = readStream.Length - readStream.Position
        End If

        If count < 0 Then
            ' Durch 0-Byte-Lesevorgang terminierte Kopier-Schleife
            ' Ein NetworkStream würde ein Timeout-Problem verursachen
            Do
                Dim portion = readStream.Read(buf, 0, bufSize)
                If portion = 0 Then Return
                writeStream.Write(buf, 0, portion)
            Loop
        Else
            ' Zählergesteuerte Kopier-Schleife
            Do
                If count < bufSize Then bufSize = CInt(count)
                Dim portion = readStream.Read(buf, 0, bufSize)
                If portion = 0 Then Throw New ArgumentException("Die " & _
                    "angegebene Anzahl Bytes konnte nicht aus dem Lese-", _
                    "Stream gelesen werden readStream + count")
                count -= portion
                writeStream.Write(buf, 0, portion)
            Loop Until count = 0
        End If
    End Sub

End Module

Ihre Meinung  

Falls Sie Fragen zu diesem Artikel haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.

WriteTo - Dwargh 16.07.12 13:47 5 Antworten