Inhaltsverzeichnis

6.2.0 Stream-Input-Output-Funktionen

In den folgenden Abschnitten werden Ihnen Stream-Input-Output-Funktionen vorgestellt. Beispiele ergänzen die Beschreibungen.

6.2.0.1 OPEN

Stream = OPEN FileName [ FOR [ READ | INPUT ] [ WRITE | OUTPUT ] [ CREATE | APPEND ] [ WATCH ] ]

Öffnet einen Stream zum Lesen, Schreiben, Erzeugen oder zum Hinzufügen von Daten – optional auch zum Beobachten. Der Stream muss existieren oder es muss zusätzlich das Schlüsselwort CREATE verwendet werden.

6.2.0.2 CLOSE

CLOSE [ # ] hStream
hStream.Close()

Beide Anweisungen schließen einen geöffneten Stream. Diese Anweisungen scheitern nie. Wenn Sie einen Prozess-Stream geöffnet haben, dann schließt er seine Standard-Eingabe – so, als ob Sie die Tasten-Kombination CTRL+D in einem Terminal eingeben würden. Die Standard-Eingabe und die Standard-Ausgabe beziehen sich auf die Daten-Kanäle in einer Konsole.

6.2.0.3 OPEN STRING

Stream = OPEN STRING [ aString ] [ FOR [ READ ] [ WRITE ] ]

Mit dem Befehl OPEN STRING können Sie auf einen String mit der Stream-Schnittstelle zugreifen.

Wenn Sie nach dem Öffnen die Tag-Eigenschaft mit einem Wert – wie hStringStream.Tag = „open“ – belegen, dann haben Sie die Möglichkeit zu prüfen, ob der StringStream bereits geschlossen wurde.

6.2.0.4 CLOSE StringStream

String = CLOSE [ # ] StringStream

Das Schließen eines String-Streams gibt den kompletten Inhalt des internen String-Stream-Puffers zurück.

Beispiel

' Gambas class file
 
Public sLog As String
Public hLogStream As Stream
Public fTemperature As Float
 
Public Sub Form_Open()
  hLogStream = Open String sLog For Write
  SetLogHeader()  
  LogTimer.Delay = 1 * 1000
  LogTimer.Start()
End
 
Public Sub btnReadFromStreamString_Click()
  TextArea1.Text = Close #hLogStream
  hLogStream = Open String sLog For Write
  SetLogHeader()
End
 
Public Sub SetLogHeader()  
  Write #hLogStream, "PROTOKOLL" & gb.NewLine
  Write #hLogStream, "Datum: " & Format(Now, "dd. mmmm yyyy") & gb.NewLine
  Write #hLogStream, String$(38, "-") & gb.NewLine  
End
 
Public Sub LogTimer_Timer()
 
' fTemperature = Round(RS232_Value,-2)
  fTemperature = Round(Rnd(19, 20), -1)
 
  Write #hLogStream, Format(Now, "hh:nn:ss") & "  |  " & "T = " & Str(fTemperature) & " °C"
  Write #hLogStream, gb.NewLine
 
End

Für den praktischen Einsatz können Sie die im o.a. Beispiel zufällig erzeugten Temperaturwerte durch die Temperaturwerte auch einer RS232-Schnittstelle mit Temperatursensor auslesen.

So sieht ein Protokoll-Auszug aus:

PROTOKOLL
Datum: 08. November 2018
--------------------------
09:36:31  |  T = 19,7 °C
09:36:32  |  T = 20,0 °C
09:36:33  |  T = 19,1 °C
09:36:34  |  T = 19,2 °C
09:36:35  |  T = 20,0 °C
09:36:36  |  T = 19,9 °C

6.2.0.5 WRITE

(a) Schreiben von Daten eines bestimmten Datentyps

Die erste Syntax schreibt einen Ausdruck in den Stream wStream, indem dessen binäre Darstellung verwendet wird.

Beispiel

Sie können ein String-Array in einer Datei abspeichern und es so exportieren. Ein Array wird über Write serialisiert in eine Datei geschrieben. Der Inhalt der Datei besitzt ein gambas-spezifisches Datei-Format:

Public hFile As File
Public aNames As String[]
...
' Data export
If Dialog.SaveFile() Then Return 
hFile = Open Dialog.Path For Write Create
Write #hFile, aNames As ARRAY
Close #hFile 

(b) Schreiben des Inhalts einer Zeichenkette

Die zweite Syntax schreibt eine bestimmte Anzahl von Bytes – angegeben durch den Wert Length – aus dem String wString in den angegebenen Stream.

Ist der Stream nicht angegeben, wird die Standard-Ausgabe verwendet. Wenn Length nicht angegeben ist, wird die Länge von wString verwendet.

(c) Schreiben des Speicherinhalts

Die dritte Syntax schreibt eine bestimmte Anzahl von Bytes – angegeben durch den Wert Length – von der Speicheradresse Pointer in den angegebenen Stream.

6.2.0.6 PRINT

PRINT [ # hStream , ] Expression [ { ; | ;; | , } Expression ... ] [ { ; | ;; | , }  ]

Die Anweisung schreibt den Inhalt von Expression in den Stream hStream.

6.2.0.7 READ

(a)	Variable = READ [ # rStream ] AS Datatype
(b)	Variable = READ [ # rStream , ] iLength

(a) Lesen von Daten eines bestimmten Datentyps

Beispiel

Wurde ein Array über Write serialisiert in einen (Datei-)Stream geschrieben wurde, so kann das Array mit Read aus diesem ausgelesen werden:

Public hFile As File
Public aNames As String[]
...
' Data import
If Dialog.OpenFile() Then Return 
hFile = Open Dialog.Path For Read
aNames = Read #hFile As ARRAY
Close #hFile 

(b) Lesen des Inhalts eines Streams

Beispiel

Public sTemperatureDigit As String
 
hRS232 = New SerialPort As "hRS232"
 
Public Sub hRS232_Read()
  sTemperatureDigit  = Read #hRS232, Lof(hRS232)
End

6.2.0.8 LINE INPUT

LINE INPUT [ # hStream , ] Variable

Liest eine Text-Zeile aus dem Text-Stream in eine String-Variable.

Ist der Stream hStream nicht angegeben, dann wird die Standard-Eingabe verwendet. Es wird stets die komplette Zeile gelesen – mit Ausnahme des Zeilenendezeichens. Standardmäßig ist es die Konstante gb.Unix, die ein einzelnes Chr$(10)-Zeichen repräsentiert. Das Zeilenendezeichen kann mit der Eigenschaft Stream.EndOfLine definiert werden.

Beispiel 1

Public Sub AddTextToFile(FilePath As String, Text As String)
 
  Dim hFile As File
 
  Try hFile = Open FilePath For Append
  Print #hFile, Text
 
  Finally
    If Exist(FilePath) Then Close #hFile
  Catch
    Message.Error("Error:\n" & Error.Text & " in " & Error.Where)
 
End
 
Public Function GetTextFromFile(FilePath As String) As String
 
  Dim hFile As File
  Dim sLine, Text As String
 
  Try hFile = Open FilePath For Read  
 
  While Not Eof(hFile)
    Line Input #hFile, sLine
    Text &= sLine & "\n"
  Wend
 
  Return Text
 
  Finally
    If Exist(FilePath) Then Close #hFile
  Catch
    Message.Error("Error:\n" & Error.Text & " in " & Error.Where)
 
End
 
Public Sub btnAddTextToFile_Click()
 
  Dim sLogDir As String
 
  sLogDir = Desktop.DataDir &/ "gambasbook" &/ Application.Name 
  If Not Exist(sLogDir) Then Shell.MkDir(sLogDir)
 
  AddTextToFile(sLogDir &/ "rs232.log", "Time = " & Format(Now, "hh:nn:ss"))
  Catch
    Message.Error("Error:\n" & Error.Text & " in " & Error.Where)
 
End
 
Public Sub btnGetTextFromFile_Click()
 
  Dim sLogPath As String
 
  sLogPath = Desktop.DataDir &/ "gambasbook" &/ Application.Name &/ "rs232.log"
  txaLog.Text = GetTextFromFile(sLogPath)
 
End

Beispiel 2

Über die Standard-Eingabe (Terminal) werden Zeichen eingelesen, um damit den MediaPlayer zu steuern. Hinweise finden Sie auf: http://www.mplayerhq.hu/DOCS/man/de/mplayer.1.html.

' Gambas module file
 
Public mPlayer As New MediaPlayer
 
Public Sub Main()
 If mPlayer Then mPlayer = Null
 Start()
End
 
Public Sub Start()
 
  mPlayer = New MediaPlayer
  mPlayer.URL = "http://mp3channels.webradio.rockantenne.de/classic-perlen"
 
  mPlayer.Play()
  mPlayer.Audio.Volume = 1.0
 
  Print #File.Out, ""
  Print #File.Out, "-------------------------------------"
  Print #File.Out, "Instructions for use"
  Print #File.Out, "-------------------------------------"
  Print #File.Out, "+  ▶ Audio.Volume ▲"
  Print #File.Out, "-  ▶ Audio.Volume ▼"
  Print #File.Out, "p  ▶ Player.Pause"
  Print #File.Out, "r  ▶ Player.Run (After a pause)"
  Print #File.Out, "m  ▶ Audio.Mute (off/on)"
  Print #File.Out, "q  ▶ Player.Stop"
  Print #File.Out, "-------------------------------------"
  Print #File.Out, "Each command is followed by <ENTER>."
  Print #File.Out, "-------------------------------------"
  Print #File.Out, ""
 
End
 
Public Sub Application_Read()
 
  Dim sInput As String
  Dim fDeltaVolume As Float
 
  If mPlayer.Audio.Volume > 1.1 Then
    fDeltaVolume = 1.0
  Else
    fDeltaVolume = 0.1
  Endif
 
  Line Input #File.In, sInput
 
  Select Case sInput
    Case "q"
      mPlayer.Stop()
      Quit
    Case "p"
      mPlayer.Pause()
    Case "r" ' run
      mPlayer.Play()
    Case "m" ' toggle switch: mute on/mute off
      mPlayer.Audio.Mute = Not mPlayer.Audio.Mute
    Case "+"
      If mPlayer.Audio.Volume > 0.09 And mPlayer.Audio.Volume < 9.0 Then
         mPlayer.Audio.Volume += fDeltaVolume
      Endif
    Case "-"
      If mPlayer.Audio.Volume > 0.2 And mPlayer.Audio.Volume < 10.0 Then
         mPlayer.Audio.Volume -= fDeltaVolume
      Endif
  End Select
 
End

In diesem Beispiel werden Zeichen auf die Standard-Ausgabe ausgegeben (File.Out) und von der Standard-Eingabe (File.In) gelesen. Die Standard-Fehler-Ausgabe wird nicht genutzt.

6.2.0.9 INPUT FROM STREAM

INPUT FROM sStream

6.2.0.10 INPUT FROM DEFAULT

INPUT FROM DEFAULT

Leitet die Standard-Eingabe auf den Stand vor der letzten Umleitung zurück.

6.2.0.11 OUTPUT TO STREAM

OUTPUT TO sStream

6.2.0.12 OUTPUT TO DEFAULT

OUTPUT TO DEFAULT

Leitet die Standard-Ausgabe auf den Stand vor der letzten Umleitung zurück.

6.2.0.13 ERROR TO STREAM

ERROR TO eStream

Leitet die Standard-Fehlerausgabe auf den Stream eStream um. Die Standard-Fehlerausgabe wird von den Anweisungen ERROR und DEBUG verwendet. Aufrufe der Anweisung können verschachtelt werden.

6.2.0.14 ERROR TO DEFAULT

ERROR TO DEFAULT

Leitet die Standard-Ausgabe auf den Stand vor der letzten Umleitung zurück.

6.2.0.15 SEEK

SEEK [ # ] hStream , iPosition

Positioniert den Stream-Zeiger für den nächsten Lese-/Schreibvorgang. Wenn iPosition negativ ist, dann wird der Streamzeiger an eine Stelle relativ zum Ende der Datei verschoben. Um den Stream-Zeiger an das Ende einer Datei zu verschieben, müssen Sie die Lof(hStream)-Funktion verwenden.

Beispiel

Eine Text-Datei wird auf unterschiedliche Art ausgelesen. Nach der Variante 1 wird der Stream-Zeiger wieder auf den Anfang (Position 0) gesetzt und die Datei nach einer zweiten Variante noch einmal vollständig ausgelesen:

  hFile = Open $sCurrentFilePath For Input
 
' Variant 1
  hFile = Open $sCurrentFilePath For Input
  While Not Eof(hFile)
    Line Input #hFile, sLine
    sContent = sContent & sLine & gb.NewLine
  Wend
 
  sContent = sContent & gb.NewLine
 
' Variant 2
  seek">Seek #hFile, 0
  For Each sLine In hFile.Lines
    sContent = sContent & sLine & gb.Lf
  Next
 
  sContent = sContent & gb.NewLine 

6.2.0.16 Seek

iPosition = Seek ( Stream )

Gibt den aktuellen Wert des Stream-Zeigers des angegebenen Streams zurück. Der Rückgabewert iPosition ist eine Integer-Zahl vom Typ Long. Beachten Sie: Viele Stream-Typen wie zum Beispiel Prozess oder Socket besitzen keinen Stream-Pointer.

6.2.0.17 LOCK

hStream = LOCK sPath

Verwenden Sie LOCK und den angegebenen Pfad sPath, um eine systemweite Stream-Sperre zu erreichen. Wenn der angegebene Stream bereits durch einen anderen Prozess gesperrt ist (Advisory look), schlägt der Befehl fehl. Einen gesperrten Stream können Sie mit dem Befehl UNLOCK wieder entsperren.

Beispiel

Um einen zweiten Programmstart sicher zu verhindern, können Sie eine systemweite Sperre auf eine (Pseudo-)Datei legen. Bei einem weiteren Programm-Start wird in (YX) ein Fehler ausgelöst, weil bereits eine Sperre existiert. Vergessen Sie nicht, die Sperre beim Beenden des Programms wieder aufzuheben.

' Gambas class file
 
Public hLockFile As File
Public sFilePath As String
 
Public Sub _new()
 
  sFilePath = Desktop.DataDir &/ "lock.lock"
  Try hLockFile = Lock sFilePath ' <--- Step 1 (XY)
  If Error Then
     Message.Warning(Subst("&1 '&2' &3", ("There is already an instance of"), Application.Name, "!"))
     FMain.Close()
  Endif
 
End
 
' Main program ...
 
Public Sub Form_Close()
    Try Unlock hLockFile ' <--- Step 2
    FMain.Close()
End

6.2.0.18 LOCK WAIT

Stream = LOCK Path fWait Delay

6.2.0.19 UNLOCK

UNLOCK [ # ] Stream

Entsperrt einen zuvor durch einen LOCK-Befehl gesperrten Stream. Auch das Schließen des Streams bewirkt automatisch das Entsperren des Streams.

6.2.0.20 EOF (end of file)

Result = Eof ( [ hStream AS Stream ] ) AS Boolean

Die Funktion gibt TRUE zurück, wenn das Ende des Streams erreicht wurde.

Wenn hStream nicht angegeben ist, wird die Standard-Eingabe verwendet. Das Verhalten von Eof() hängt vom Stream-Blocking-Modus ab: (1) Wenn sich der Stream im Non-Blocking-Modus befindet, dann gibt Eof() den Funktionswert True zurück, wenn mindestens ein Byte aus dem Stream gelesen werden kann. (2) Wenn sich der Stream dagegen im Blockiermodus befindet, wartet Eof() zuerst auf Daten, bevor geprüft wird, ob etwas gelesen werden kann.

  hFile = Open $sCurrentFilePath For Input
  While Not Eof(hFile)
    Line Input #hFile, sLine
    sContent = sContent & sLine & gb.NewLine
  Wend

6.2.0.21 LOF (length of file)

Length = Lof ( hStream AS Stream ) AS Long

6.2.0.22 FLUSH

FLUSH [ [ # ] Stream ]

Die Daten eines gepufferten Streams werden unverzüglich ausgegeben – der Zwischenspeicher wird geleert. Wenn kein Stream angegeben ist, werden die Daten jedes geöffneten Streams ausgegeben. Sie können mit der Flush-Instruktion aber keine Daten aus einem anderen Prozess anfordern, wenn Sie dessen Daten aus einem Stream lesen wollen.

Beispiel

Es soll die Aufforderung „Geben Sie Ihren Namen ein: “ im Terminal angezeigt werden und der Cursor soll – wie üblich – in der gleichen Zeile für die Eingabe der Antwort verbleiben. Das wird durch das Doppel-Semikolon nach der Print-Instruktion geleistet. Es gibt ein Leerzeichen aus und unterdrückt den Zeilenumbruch, den Print normalerweise an die Ausgabe anhängt. Nun sind Terminals aber zeilengepuffert. Das bedeutet, dass das Gambas-Programm den ge-Print-eten String entgegennimmt und ihn puffert, bis es das nächste Zeilenende-Zeichen liest. Erst dann werden die Daten an das Terminal geschickt. Da jetzt nach der Print-Instruktion in *** aber durch das Doppel-Semikolon der Zeilenumbruch fehlt, würden Sie (ohne Flush) im Terminal keine Aufforderung zu Gesicht bekommen, obwohl das Gambas-Programm schon bei der Line-Input-Instruktion ist und auf Eingaben wartet. Probieren Sie es doch einmal ohne Flush aus und tippen einfach blind Ihren Namen ein. Es wird funktionieren, aber Sie sehen die Aufforderung erst nach der zweiten Print-Instruktion, die ein Zeilenende liefert! Mit Flush teilen Sie Gambas mit, dass es die Daten unverzüglich ausgeben soll. Damit funktioniert das Programm wie erwartet.

' Gambas module file
 
Public Sub Main()
 
  Dim sName As String
 
  Print "Enter your name:";; ' ***
  Flush
 
  Line Input sName
  Print "Good to know that you are " & sName;
  Print 
 
End

Programm-Start im Projektverzeichnis:

hans@mint-183 ~/GB3BUCH/6K_Stream/6.2.0_Stream-Input-Output-Funktionen/Projekte/Flush $ gbr3 flush.gambas
Enter your name: Mister Red              
Good to know that you are Mister Red

6.2.0.23 NAMED PIPE

hStream = PIPE sPipeName FOR [ READ ] [ WRITE ] [ WATCH ]
hStream = OPEN PIPE sPipeName FOR [ READ ] [ WRITE ] [ WATCH ]

Eine ausführliche Beschreibung zu Named Pipes finden Sie im Kapitel 6.2.2.

Download