none
Wie kann man eine Datei byteweise (nicht zeichenweise) lesen und schreiben? RRS feed

  • Frage

  • Windows 7 - VisualBasic 2010 Express - Anfänger/Umsteiger von VB6, Autodidakt

    Die beträchtlichen Änderungen von VB6 auf VB2010 haben den Aufruf und das Öffnen von Dateien sehr vereinfacht. Ich finde aber keine Anweisungen mehr zum byteweisen Lesen und Schreiben einer Datei.

    Was habe ich:

    - Eine ganze Datei (Textdatei in Codierung Cp 1252 oder Unicode mit Kennung) lese ich auf einmal (hier in die TextBox1) mit

    Dim lese1 As New System.IO.StreamReader(OpenFileDialog1.FileName, System.Text.Encoding.Default)
                    TextBox1.Text = lese1.ReadToEnd

    - Eine ganze Datei (Textdatei in Codierung Cp 1252 oder Unicode mit Kennung) lese ich zeilenweise (hier in die TextBox1) mit

    Dim lese2 As New System.IO.StreamReader(OpenFileDialog1.FileName, System.Text.Encoding.Default)
                    Dim z As String
                    Do Until lese2.Peek() = -1
                        z = lese2.ReadLine()
                        TextBox1.Text = TextBox1.Text & z & vbCrLf
                    Loop

    - Eine ganze Datei (Textdatei in Codierung Cp 1252 oder Unicode mit Kennung) lese ich zeichenweise (hier in die TextBox1) mit

    Dim lese3 As New System.IO.StreamReader(OpenFileDialog1.FileName, System.Text.Encoding.Default)
                    Dim y As Integer
                    Do Until lese3.Peek() = -1
                        y = lese3.Read
                        TextBox1.Text = TextBox1.Text & ChrW(y) & vbCrLf
                    Loop

    Was möchte ich:

    Eine ganze Datei (ohne Rücksicht auf ihre Codierung, also eine 'Binärdatei') byteweise (nicht zeichenweise!) lesen (und später schreiben). Natürlich soll sie nicht wie in den obigen Beispielen in eine TextBox gelesen, sondern sofort bearbeitet werden. Unter VB6 konnte ich das mit GET und PUT machen. In VB10 finde ich keine passende Anweisungen.

    Ich bitte um Nachsicht für die langatmige Darstellung und danke für jede Anregung.

    Werner314

    Dienstag, 26. Juli 2011 09:01

Antworten

  • Hallo Werner,

    Kern für Datenzugriffe ist ein Stream, womit die grundlegenden Operationen definiert werden,
    die dort immer auf Byte-Ebene üblicherweise über ein Byte-Array erfolgen.

    Für Dateien ist die stellt die FileStream Klasse die Implementiert für einen Stream bereit.

    Alle Streams können über einen BinaryReader bzw. BinaryWriter binär verarbeitet werden.
    Die Klassen stellen dabei den Zugriff für die primitiven Datentypen (wie Integer, Double usw.) bereit.

    StreamReader und StreamWriter wiederum sind Klassen für textbasierten Zugriff,
    basierend auf den abstrakten TextReader- und TextWriter-Klassen,
    d. h. sie interpretieren die Bytes in einem Stream anhand des Encodings -
    .NET arbeitet im Standard mit UTF8-Kodierung.

    Bei der Verarbeitung sollte man grundsätzlich beachten, die Datei nach dem Zugriff zu schliessen.
    Damit das auch im Falle eines Fehlers passiert, empfiehlt sich der Einsatz der using Anweisung.
    Exemplarisch für Dein erstes Beispiel:

    Using lese1 As New System.IO.StreamReader(OpenFileDialog1.FileName, System.Text.Encoding.Default)
      TextBox1.Text = lese1.ReadToEnd()
    End Using
    
    
    Einige weitere Beispiele für Textdateien: Textdateien zeilenweise auslesen und zerlegen.

    Für mehr schau Dir mal an: Grundlegende Datei-E/A.

    Gruß Elmar

    P. S.: Allgemeine Fragen zu Visual Basic sind im Visual Basic .NET Forum besser aufgehoben.

    Dienstag, 26. Juli 2011 11:42
  • Hallo Werner,

    sobald Du einen StreamReader verwendest, wird die Datei als Textdatei behandelt -
    StreamReader ist von TextReader abgeleitet, was den Zusammenhang deutlich machen sollte.

    Und Text sind keine Bytes mehr, zumindest bei den komplexeren Zeichensätzen wie UTF-8
    wo ein Zeichen ein bis vier Bytes beanspruchen kann.
    Die vom StreamReader in Unicode (UCS-2) umgewandelt werden, womit .NET intern arbeitet.

    Würde man da einfach ein Byte zwischen weglesen, gibt es Zeichensalat -
    und so ist aus gutem Grund ReadByte nicht mehr (direkt) erreichbar.

    Nackte Bytes kannst Du bereits mit dem FileStream selbst lesen.
    Der BinaryReader/-Writer erweitert den Stream, und ermöglicht die primitiven Datentypen sauber zu verarbeiten -
    denn auch da kann es durch die Byte-Reihenfolge (Endianess) ansonsten Probleme geben.

    Ein sehr einfaches Beispiel:

    Option Explicit On
    Option Infer On
    Option Strict On
    
    Imports System.Diagnostics
    Imports System.IO
    
    Class BinaryFile
     ' Dateiname für das Beispiel, entsprechend anpassen
     Const DateiName As String = "C:\TEMP\Datei.dat"
    
     ' ABCDEabcde
     Private Shared ReadOnly TestDaten As Byte() = {&H41, &H42, &H43, &H44, &H45, &H61, &H62, &H63, &H64, &H65}
    
     Friend Shared Sub BinärSchreibenUndLesen()
     Using writer As New BinaryWriter(New FileStream(DateiName, FileMode.Create, FileAccess.Write, FileShare.None))
      ' Länge schreiben
      writer.Write(TestDaten.Length)
    
      ' Byte für Byte schreiben
      For index = 0 To TestDaten.Length - 1
      writer.Write(TestDaten(index))
      Next
    
      ' Effizienter wäre
      'writer.Write(TestDaten)
     End Using
    
     ' Lesen der geschriebenen Daten
     Dim daten As Byte()
     Using reader As New BinaryReader(New FileStream(DateiName, FileMode.Open, FileAccess.Read, FileShare.Read))
      ' Länge lesen
      Dim length = reader.ReadInt32()
    
      ' Dimensionieren
      daten = New Byte(length - 1) {}
    
      ' Byteweise Lesen
      For index = 0 To length - 1
      daten(index) = reader.ReadByte()
      Next
    
      ' Effizienter wäre
      ' Dim daten = reader.ReadBytes(length)
     End Using
    
     ' Gelesene Daten vergleichen
     Debug.Assert(TestDaten.Length = daten.Length, "Länge abweichend")
     For index = 0 To TestDaten.Length - 1
      Debug.Assert(TestDaten(index) = daten(index), "Byte abweichend an " & index.ToString())
     Next
     End Sub
    End Class
    
    

    was Du als eine neue Klasse einfügen kannst und  in einem Windows Forms Projekt
    über einen Button starten kannst mit:

     Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
     BinaryFile.BinärSchreibenUndLesen()
     End Sub
    
    

    Zu den MSDN Beispielen:
    Die Beispiele sind zwar häufig als Konsolenprojekte konzipiert - die man mit Visual Basic ebenso erstellen kann.
    Wenn Du sie aber lieber in einem Windows Form Projekt haben möchtest, so reicht es im allgemeinen
    den Abschnitt aus Sub Main() in eine Shared Sub mit anderem Namen zu übertragen und zugehörige Klassen ebenso.
    Die  Main Prozedur ist reserviert als Einstiegspunkt und sollte nur einmalig im Projekt vorkommen.

    Gruß Elmar



    Sonntag, 31. Juli 2011 15:39

Alle Antworten

  • Hallo Werner,

    Kern für Datenzugriffe ist ein Stream, womit die grundlegenden Operationen definiert werden,
    die dort immer auf Byte-Ebene üblicherweise über ein Byte-Array erfolgen.

    Für Dateien ist die stellt die FileStream Klasse die Implementiert für einen Stream bereit.

    Alle Streams können über einen BinaryReader bzw. BinaryWriter binär verarbeitet werden.
    Die Klassen stellen dabei den Zugriff für die primitiven Datentypen (wie Integer, Double usw.) bereit.

    StreamReader und StreamWriter wiederum sind Klassen für textbasierten Zugriff,
    basierend auf den abstrakten TextReader- und TextWriter-Klassen,
    d. h. sie interpretieren die Bytes in einem Stream anhand des Encodings -
    .NET arbeitet im Standard mit UTF8-Kodierung.

    Bei der Verarbeitung sollte man grundsätzlich beachten, die Datei nach dem Zugriff zu schliessen.
    Damit das auch im Falle eines Fehlers passiert, empfiehlt sich der Einsatz der using Anweisung.
    Exemplarisch für Dein erstes Beispiel:

    Using lese1 As New System.IO.StreamReader(OpenFileDialog1.FileName, System.Text.Encoding.Default)
      TextBox1.Text = lese1.ReadToEnd()
    End Using
    
    
    Einige weitere Beispiele für Textdateien: Textdateien zeilenweise auslesen und zerlegen.

    Für mehr schau Dir mal an: Grundlegende Datei-E/A.

    Gruß Elmar

    P. S.: Allgemeine Fragen zu Visual Basic sind im Visual Basic .NET Forum besser aufgehoben.

    Dienstag, 26. Juli 2011 11:42
  • Vielen Dank für die freundlichen Antworten. Unmittelbar gehelfen haben sie mir leider nicht. Aber das liegt an mir. Ich muss offensichtlich noch viel lernen, was die Strukturen von VB10 betrifft.

    Immerhin hatte ich verstanden und einrichten können, dass das Lesen einer Datei möglich ist mithilfe von

    System.IO.StreamReader(OpenFileDialog1.FileName)

    Dabei wird sie mit

    .ReadToEnd

    am Stück (als UTF-8-codiert) gelesen, mit

    .ReadLine

    zeilenweise (als UTF-8-codiert) gelesen und mit

    .Read

    zeichenweise (als UTF-8-codiert) gelesen.

    Was liegt näher, als das byteweise Lesen zu versuchen mit

    .ReadByte

    Aber: '"ReadByte" ist kein Member von "System.IO.StringReader".'

    Anstelle von 'StreamReader' 'BinaryReader' zu verwenden scheint mir nicht logisch, denn ich will ja den 'Datenstrom' einer Datei lesen, wenn auch byteweise. Trotzdem probiert, aber unter Verwendung von

    System.IO.BinaryReader(OpenFileDialog1.FileName)

    bekomme ich dann die Meldung: 'Der Wert vom Typ "String" kann nicht in "System.IO.Stream" konvertiert werden.' Das ist für mich unverständlich.

    Die Beispiele in MSDN helfen mir oft deshalb nicht weiter, weil sie für Console eingerichtet sind und och damit (noch) nicht arbeiten kann.

    Dank und freundliche Grüße

    Werner314

    Samstag, 30. Juli 2011 16:27
  • Hallo Werner,

    sobald Du einen StreamReader verwendest, wird die Datei als Textdatei behandelt -
    StreamReader ist von TextReader abgeleitet, was den Zusammenhang deutlich machen sollte.

    Und Text sind keine Bytes mehr, zumindest bei den komplexeren Zeichensätzen wie UTF-8
    wo ein Zeichen ein bis vier Bytes beanspruchen kann.
    Die vom StreamReader in Unicode (UCS-2) umgewandelt werden, womit .NET intern arbeitet.

    Würde man da einfach ein Byte zwischen weglesen, gibt es Zeichensalat -
    und so ist aus gutem Grund ReadByte nicht mehr (direkt) erreichbar.

    Nackte Bytes kannst Du bereits mit dem FileStream selbst lesen.
    Der BinaryReader/-Writer erweitert den Stream, und ermöglicht die primitiven Datentypen sauber zu verarbeiten -
    denn auch da kann es durch die Byte-Reihenfolge (Endianess) ansonsten Probleme geben.

    Ein sehr einfaches Beispiel:

    Option Explicit On
    Option Infer On
    Option Strict On
    
    Imports System.Diagnostics
    Imports System.IO
    
    Class BinaryFile
     ' Dateiname für das Beispiel, entsprechend anpassen
     Const DateiName As String = "C:\TEMP\Datei.dat"
    
     ' ABCDEabcde
     Private Shared ReadOnly TestDaten As Byte() = {&H41, &H42, &H43, &H44, &H45, &H61, &H62, &H63, &H64, &H65}
    
     Friend Shared Sub BinärSchreibenUndLesen()
     Using writer As New BinaryWriter(New FileStream(DateiName, FileMode.Create, FileAccess.Write, FileShare.None))
      ' Länge schreiben
      writer.Write(TestDaten.Length)
    
      ' Byte für Byte schreiben
      For index = 0 To TestDaten.Length - 1
      writer.Write(TestDaten(index))
      Next
    
      ' Effizienter wäre
      'writer.Write(TestDaten)
     End Using
    
     ' Lesen der geschriebenen Daten
     Dim daten As Byte()
     Using reader As New BinaryReader(New FileStream(DateiName, FileMode.Open, FileAccess.Read, FileShare.Read))
      ' Länge lesen
      Dim length = reader.ReadInt32()
    
      ' Dimensionieren
      daten = New Byte(length - 1) {}
    
      ' Byteweise Lesen
      For index = 0 To length - 1
      daten(index) = reader.ReadByte()
      Next
    
      ' Effizienter wäre
      ' Dim daten = reader.ReadBytes(length)
     End Using
    
     ' Gelesene Daten vergleichen
     Debug.Assert(TestDaten.Length = daten.Length, "Länge abweichend")
     For index = 0 To TestDaten.Length - 1
      Debug.Assert(TestDaten(index) = daten(index), "Byte abweichend an " & index.ToString())
     Next
     End Sub
    End Class
    
    

    was Du als eine neue Klasse einfügen kannst und  in einem Windows Forms Projekt
    über einen Button starten kannst mit:

     Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
     BinaryFile.BinärSchreibenUndLesen()
     End Sub
    
    

    Zu den MSDN Beispielen:
    Die Beispiele sind zwar häufig als Konsolenprojekte konzipiert - die man mit Visual Basic ebenso erstellen kann.
    Wenn Du sie aber lieber in einem Windows Form Projekt haben möchtest, so reicht es im allgemeinen
    den Abschnitt aus Sub Main() in eine Shared Sub mit anderem Namen zu übertragen und zugehörige Klassen ebenso.
    Die  Main Prozedur ist reserviert als Einstiegspunkt und sollte nur einmalig im Projekt vorkommen.

    Gruß Elmar



    Sonntag, 31. Juli 2011 15:39