The following sections introduce you to stream input-output functions. Examples supplement the descriptions.
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.
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.
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.
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
(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.
PRINT [ # hStream , ] Expression [ { ; | ;; | , } Expression ... ] [ { ; | ;; | , } ]
The instruction writes the contents of Expression to the stream hStream.
(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
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.
INPUT FROM sStream
INPUT FROM DEFAULT
Redirects the standard input to the state before the last redirection.
OUTPUT TO sStream
OUTPUT TO DEFAULT
Redirects the standard output to the state before the last redirection.
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.
ERROR TO DEFAULT
Redirects the standard output to the state before the last redirection.
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
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.
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
Stream = LOCK Path fWait Delay
UNLOCK [ # ] Stream
Unlocks a stream previously locked by a LOCK command. Closing the stream also automatically unlocks the stream.
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
Length = Lof ( hStream AS Stream ) AS Long
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
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.