Binary File (2/2)

Binary File (2/2). Datenwiederherstellung.

Im ersten Teil dieses Beispiels habe ich gezeigt, wie man Objekte die aus einer Klasse instanziert wurden in einer Collection speichert um diese mittels BinaryFormatter in ein binäres File zu streamen. Im zweiten Teil möchte ich nun den umgekehrten Weg zeigen, nämlich wie man die Daten von der Platte wieder in die Anwendung bekommt.

Analog dem ersten Beispiel brauchen wir also einen Deserialisierer um die Daten aus unserem Binärfile zurückzulesen und zugreifbar zu machen. Um an den ersten Teil anzuknüpfen, führe ich die Nummerierung fort:

4. Deserialize. Wir fügen dem BinaryFile-Modul eine neue Funktion “Deserialize” hinzu. Hierin definieren wir zunächst eine leere Hashtable um den Inhalt der binären Datei aufzunehmen. Danach gehen wir analog der Serialisation den Weg über einen FileStream verbunden mit einem BinaryFormatter um auf die Wertedatei zuzugreifen. Wir casten den deserialisierten Inhalt der Datei als Hashtable und… fertig.

Private Sub Deserialize()
    Dim oItemCollection As Hashtable
    Dim oFileReader As FileStream
    Dim oFormatter As BinaryFormatter

    'Define our Collection. Corresponding to the Collection used
    'in the Serialize()-Function it’s a hashtable here.
    oItemCollection = new Hashtable
    oItemCollection = Nothing
    'We want to read from our binary data file, so we initialize
    'a Filestream
    oFileReader = New FileStream(“DataFile.dat”, FileMode.Open)

    Try
        oFormatter = New BinaryFormatter
        'Read entire file and direct cast it into our hashtable Collection
        oItemCollection = DirectCast(oFormatter.Deserialize(oFileReader), Hashtable)
    Catch e As SerializationException
        Console.WriteLine(“Deserialization failed. Reason: “ & e.Message)
        Throw
    Finally
        oFileReader.Close()
    End Try
End Sub

Unsere im ersten Teil eingetragenen Daten sind nun also über die Hastable wieder im Zugriff.

Weitere Schritte. In der EInleitung zum ersten Teil wurde postuliert, dass man auf der binären Datei arbeiten kann wie auf einer einfachen Datenbank. Das ist durchaus richtig aber nicht ganz korrekt formuliert, denn wie sich jetzt schon gezeigt hat, arbeiten wir ja nicht auf der Datei selber sondern führen alle weiteren Operationen auf der Collection aus. Hier also auf einer Hashtable.

Hashtables sind ein Kapitel für sich, dennoch möchte ich hier kurz auf zwei wesentliche Funktionalitäten eingehen um den Umgang mit Daten in diesem Beispiel zu komplettieren. Sicherlich ist der gezeigte Weg nicht unbedingt das Optimum, aber es zeigt, wie einfach auf unserer Datenmenge gearbeitet werden kann.

Zugriff auf bestimmte Keys. Der Zugriff auf Schlüsselwerte ist – wie erwartet – einfach. Hierzu muss nur die Collection auf einen Schlüsselwert abgefragt werden.

Dim iRandomNumber As Integer

Randomize()

'Get random number to check against the hashtable keys
iRandomNumber = CInt(Rnd() * 1000)       

If ItemCollection.ContainsKey(“Key” & iRandomNumber) Then
    Console.WriteLine(“The Key {0} was found in our Collection and has a Value of {1}”, iRandomNumber, ItemCollection.Item(“Key” & iRandomNumber).Value)
Else
    Console.WriteLine(“The value {0} was not found.”, iRandomNumber)
End If
Werte finden. Die von uns anfänglich randomisierten Werte sind ebenfalls einfach auffindbar. Im Worst-Case-Fall benötigen wir hier einen kompletten Durchlauf durch die Collection. Wenn man aber davon ausgeht, dass die Datenmengen eher moderat sein werden, weil sonst definitiv eine “große Datenbank” Sinn gemacht hätte, lässt sich dieses Manko mit der Performance wett machen.
'Let’s find some Item.Value
'Therefore we are make use of Dictionaries
Dim Entry As DictionaryEntry

'how often does this value exists in the entire Collection 
Dim iCounter As Integer = 0

'Current Value
Dim iValue As Integer

'Loop through the entire Collection
For Each Entry In ItemCollection
    'Extract Value from Collection-item
    iValue = DirectCast(Entry.Value, cItem).Value

    'If it is the Value we are looking for, then increment counter
    If iValue = iRandomNumber Then
        iCounter += 1
    End If
Next

Console.WriteLine(“The value {0} was found {1} times”, iRandomNumber, iCounter) 

Ergebnis. Ich habe gezeigt, dass auch die Deserialisation auf Binary Files einfach und schnell umgesetzt werden kann. Bezüglich dem Zugriff auf Werte oder Keys habe ich ebenfalls einfache Beispiele gezeigt. Hier konnte man sehen dass man im Worst-Case mit einem kompletten Collection-Durchlauf Zugriff auf alle Werte und Keys erhalten kann. Das ist Performance-Technisch wohl in der Regel auch nicht so kritisch.

Natürlich kann man bezüglich der Laufzeiten hier eine Menge tun. Angefangen von der sinnvollen Auswahl der Collection und das weise Design der Werte-Klasse bis hin zu Funktionalitäten und Operationen die direkt auf den Collections zur Verfügung stehen oder diese effektiv erweitern. Als Einstieg in Binary Files soll das hier aber erstmal genügen.

Binary File (1/2)

Binary File (1/2). Datenspeicherung per Serialisation.

Dann und wann kommt man an den Punkt an dem man eine .Net-Applikation entwickelt, die Daten speichern muss. In den meisten Fällen wird man in Richtung Datenbanken gehen um Daten (relational) zu halten, in manchen Fällen jedoch ist entweder keine Datenbank nötig oder eine Datenbank steht nicht zur Verfügung.

Der populärste Weg eine Anwendung zu entwickeln die mit strukturierten Daten hantiert aber keine klassische Datenbank wie MSSQL nutzt, wäre mit XML zu arbeiten. Grundsätzlich verrichtet XML eine großartige Arbeit und wenn man ein wenig mit XML vertraut ist, kann man in .Net mit einem starken Funktionsportfolio schnell und effektiv arbeiten.

Aber da ist noch mehr.

In diesem Artikel werde ich einen näheren Blick auf eine Technologie werfen, die es erlaubt einfach und unkompliziert Objekte mit Hilfe von Serialisation zu speichern. Zudem ist der Zugriff und die Arbeit mit dieser Technologie durchaus vergleichbar mit dem Arbeiten auf einer einfachen Datenbank. Grund genug sich damit näher zu beschäftigen.

Wir brauchen erstmal nur drei Zutaten für unser System:

  1. Eine Klasse aus der wir Objekte instanzieren können (um sie später zu speichern)
  2. Eine Art von Collection in die Objekte gepusht werden können (in unserem Fall eine Hashtable)
  3. Ein Binary Writer um unsere Daten tatsächlich auf die Platte zu speichern.

Da die Theorie hier verwirrender klingt als es eigentlich ist, ein komplettes Beispiel.

Vorbereitung. In VS2005 erstellen wir eine neue Command Line Application in VB.net. Das initiale “Module1″-Modul benennen wir in “Binarywriter” um und speichern das Projekt an einem geeigneten Ort. Nachdem das geschehen ist, können nun die einzelnen Komponenten hinzugefügt werden die wir oben mit den drei Zutaten definiert haben

1. Die Klasse. Als erstes fügen wir eine neue Klasse hinzu die “cItem” [1] heißt und geben dieser eine Property.

Public Class cItem

    Private _dValue As Double


    Public Property Value()
        Get
            Return _ dValue
        End Get
        Set(ByVal Value)
            _ dValue = (Value * 1000)
        End Set
    End Property
End Class

Aus diese Klasse rekrutieren sich die späteren Objekte die wir mit Hilfe einer Collection als binäre Datei speichern wollen.

2. Die Collection. Gehen wir zurück zu unserem “BinaryWriter”-Modul und fügen, um die zweite Zutat nutzen zu können, ein paar Import-Statements ein:

Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Runtime.Serialization

Hiernach kommen wir zur eigentlichen Erstellung der Collection und der Befüllung der neuen Collection durch eine größere Anzahl von randomisierten Werten. Die Einzelwerte werden jeweils durch Objekt-Instanzen der cItem-Klasse gebildet.

Private Sub Serialize()
    'define our Collection – a hashtable in our case
    'because it will hold all the Items we are going to
    'create, we will call it ItemCollection
    Dim oItemCollection As New Hashtable
    Dim oItem As Object
    Dim iCounter As Integer

    'We will fill our Data-File with a mass of values
    For iCounter = 1 To 10000
        'Make new Item from cItems
        oItem = New cItem
        Randomize()
        'Give it a random Value
        oItem.Value = Rnd()
        'Add it to our collection
        oItemCollection.Add(“Key” & iCounter , oItem)
        'destroy our Item
        oItem = Nothing
    Next
End Sub
3. Der Binary Writer. Nun können wir die Daten in unserer gefüllten Collection als binäre Datei speichern. Hierzu benötigen wir einen FileStream und einen BinaryFormatter um die Collection in eine angegebene Datei zu streamen.
Private Sub Serialize()
    (...)

    'As we want to write a binary file, we need to open a
    'FileStream to create one. That’s why we need the System.IO
    'Import for, btw.
    Dim oFileWriter As New FileStream(“DataFile.dat “, FileMode.Create)
    'Construct a BinaryFormatter and use it to serialize the data
    'to the stream. 
    Dim oFormatter As New BinaryFormatter
    Try
        oFormatter.Serialize(oFileWriter, oItemCollection)
    Catch e As SerializationException
        Console.WriteLine(“Serialization failed. Reason: “ & e.Message)
        Throw
    Finally
        oFileWriter.Close()
    End Try
End Sub

Ergebnis. Damit haben wir auch schon gezeigt was ich in diesem Artikel vorstellen wollte. Nämlich dass man sehr einfach Daten in eine binäre Datei schreiben kann.  Die Alternative, Objekte in einer Collection zu halten, um sie zu serialisieren, hat in manchen Anwendungsgebieten durchaus Vorteile. Es muss halt nicht immer “die große Datenbank” sein.

Da man als Collection grundsätzlich alle Typen von Collections nutzen kann, kann man hier mit einer sinnvollen Auswahl und einem sinnvollen Design der Daten-Klasse viele Vorteile nutzen um sauberen und effizienten Code zu erhalten und damit eine robuste Anwendung. Eine Hashtable habe ich hier exemplarisch eingesetzt und bietet sich eigentlich hauptsächlich bei alphabetischen Keys an.

Anmerkung. Das oben gezeigte funktioniert leider nicht beim .Net Compact Framework.


[1] Ich weiss das Manche nun sagen werden, dass “cItem” nicht der gängigen Namenskonvention in .Net entspricht. Das mag auch für andere Dinge in meinem Code gelten. Dem möchte ich auch nicht widersprechen, aber was ich hier tue ist, die Namenskonventionen meines Unternehmens zu benutzen. Und das nicht nur, weil ich sie entwickelt habe ;)

Sourcecode in WordPress

Wer hätte gedacht dass die meiste Zeit beim Schreiben von Artikeln dafür drauf geht den Sourcecode ordentlich zu formatieren.
Sollte man doch eigentlich meinen, dass entweder der <pre>-Tag oder die “Vorformatiert”-Formatierung dieses übernehmen könnte, irrt man gewaltig. Zwar macht (gerade “Vorformatiert”) das was ich will und sieht auch schick aus, aber leider kommt WordPress aus mir nicht näher bekannten Gründen damit nicht zu rande und zerschießt mir ständig die als Sourcecode formatierten Stellen.

Nach vielem Fluchen und suchen präferiere ich nun den Weg, dass ich den visuellen Editor deaktiviert habe und mit WP-Syntax oder Google Syntax Highlighter arbeite. Ganz entschieden bin ich da noch nicht.

Aber mal ehrlich: kann es so schwer sein ? Leider bietet der HTML-Editor ja leider gerade in Hinblick auf Image-Positionierung eher wenig, das ging im WYSIWYG-Editor ganz gut… Naja, man kann nicht alles haben.
Ich denke ich werde bei Zeiten mal ein wenig in das WordPress-Javascript einsteigen und versuchen rauszufinden, wo der WYSIWYG-Editor meine schön formatierten Artikel zerpflückt…

Und ich dachte, WordPress kann alles ;)