Table of Contents

6.2.0 Stream Input-Output Functions

The following sections introduce you to stream input-output functions. Examples supplement the descriptions.

6.2.0.1 OPEN

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

Opens a stream for reading, writing, creating or adding data - optionally also for watching. The stream must exist or the keyword CREATE must also be used.

6.2.0.2 CLOSE

CLOSE [ # ] hStream
hStream.Close()

Both statements close an open stream. These statements never fail. When you have a process stream open, it closes its standard input - just as if you were typing the key combination CTRL+D in a terminal. Standard input and standard output refer to the data channels in a console.

6.2.0.3 OPEN STRING

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

Use the OPEN STRING command to access a string with the stream interface.

If you set the tag property with a value - like hStringStream.Tag = “open” - after opening, then you have the possibility to check if the StringStream has already been closed.

6.2.0.4 CLOSE StringStream

String = CLOSE [ # ] StringStream

Closing a string stream returns the complete contents of the internal string stream buffer.

Example

' 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

For practical use, you can also read the randomly generated temperature values in the above example by the temperature values of an RS232 interface with temperature sensor.

This is what a protocol extract looks like:

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) Writing data of a specific data type

The first syntax writes an expression to the stream wStream by using its binary representation.

Example

You can save a string array to a file and export it that way. An array is written serialised to a file via Write. The content of the file has a gambas-specific file 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) Writing the contents of a string

The second syntax writes a specified number of bytes - specified by the Length value - from the string wString to the specified stream.

If the stream is not specified, the standard output is used.If Length is not specified, the length of wString is used.

(c) Writing the memory content

The third syntax writes a specified number of bytes - specified by the Length value - from the Pointer memory address to the specified stream.

6.2.0.6 PRINT

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

The instruction writes the contents of Expression to the stream hStream.

6.2.0.7 READ

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

(a) Read data of a specified data type *. * The first syntax reads the stream as a data stream whose type is specified by Datatype.

Example

If an array was written serialised into a (file) stream via Write, the array can be read from it with Read:

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) Read the contents of a stream

Example

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

Reads a line of text from the text stream into a string variable.

If the stream hStream is not specified, then the standard input is used. The complete line is always read - with the exception of the end-of-line character. By default, it is the constant gb.Unix, which represents a single Chr$(10) character. The end-of-line character can be defined with the Stream.EndOfLine property.

Example 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

Example 2

Characters are read in via standard input (terminal) to control the MediaPlayer. Notes can be found at: 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 this example, characters are output to standard output (File.Out) and read from standard input (File.In). The standard error output is not used.

6.2.0.9 INPUT FROM STREAM

INPUT FROM sStream

6.2.0.10 INPUT FROM DEFAULT

INPUT FROM DEFAULT

Redirects the standard input to the state before the last redirection.

6.2.0.11 OUTPUT TO STREAM

OUTPUT TO sStream

6.2.0.12 OUTPUT TO DEFAULT

OUTPUT TO DEFAULT

Redirects the standard output to the state before the last redirection.

6.2.0.13 ERROR TO STREAM

ERROR TO eStream

Redirects the standard error output to the stream eStream. The standard error output is used by the ERROR and DEBUG instructions. Calls to the instruction can be nested.

6.2.0.14 ERROR TO DEFAULT

ERROR TO DEFAULT

Redirects the standard output to the state before the last redirection.

6.2.0.15 SEEK

SEEK [ # ] hStream , iPosition

Positions the stream pointer for the next read/write. If iPosition is negative, then the stream pointer is moved to a location relative to the end of the file. To move the stream pointer to the end of a file, you must use the Lof(hStream) function.

Example

A text file is read in different ways. After variant 1, the stream pointer is set back to the beginning (position 0) and the file is read out completely again after a second variant:

  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 )

Returns the current value of the stream pointer of the specified stream. The return value iPosition is an integer number of type Long. Note: Many stream types, such as process or socket, do not have a stream pointer.

6.2.0.17 LOCK

hStream = LOCK sPath

Use LOCK and the specified path sPath to achieve a system-wide stream lock. If the specified stream is already locked by another process (advisory look), the command will fail. You can unlock a locked stream with the command UNLOCK.

Example

To safely prevent a second programme start, you can place a system-wide lock on a (pseudo) file. If another programme is started, an error is triggered in (YX) because a lock already exists. Do not forget to release the lock when you exit the programme.

' 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

Unlocks a stream previously locked by a LOCK command. Closing the stream also automatically unlocks the stream.

6.2.0.20 EOF (end of file)

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

The function returns TRUE when the end of the stream has been reached.

If hStream is not specified, the standard input is used.The behaviour of Eof() depends on the stream blocking mode: (1) If the stream is in non-blocking mode, then Eof() returns the function value True if at least one byte can be read from the stream. (2) If, on the other hand, the stream is in blocking mode, Eof() first waits for data before checking whether anything can be read.

  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 ]

The data of a buffered stream is output immediately - the buffer is emptied. If no stream is specified, the data of any open stream is output. However, you cannot use the flush instruction to request data from another process if you want to read its data from a stream.

Example

The prompt “Enter your name: ” is to be displayed in the terminal and the cursor is to remain - as usual - in the same line for entering the answer. This is accomplished by the double semicolon after the print instruction. It outputs a space and suppresses the line break that Print normally appends to the output. Now, however, terminals are line-buffered. This means that the Gambas programme receives the printed string and buffers it until it reads the next end-of-line character. Only then is the data sent to the terminal. Since the line break is missing after the print instruction in *** due to the double semicolon, you would not see a prompt in the terminal (without flush), although the Gambas programme is already at the line input instruction and waiting for input. Why don't you try it without flush and just type your name blindly. It will work, but you won't see the prompt until after the second print instruction, which returns an end-of-line! With Flush you tell Gambas to print the data immediately. This will make the programme work as expected.

' 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

Programme start in the project directory:

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 ]

A detailed description of Named Pipes can be found in Chapter 6.2.2.