Summary:
See also: Built-in classes
The Channel class provides basic read/write functionality to access files or to communicate with sub-processes.
base.Channel
Class Methods | |
Name | Description |
create() |
Creates a new channel object. |
Object Methods | |
Name | Description |
openFile( path STRING,
flags STRING ) |
Opens a channel to a file identified by path, with options.
The parameters flags can be one of:
|
openPipe( scmd STRING,
flags STRING ) |
Opens a channel to a process by executing the command scmd, with
options.
The parameters flags can be one of:
|
setDelimiter( d STRING
) |
Sets the field delimiter of the channel. The default is DBDELIMITER,
or "|" if DBDELIMITER is not defined. If you pass NULL,
no delimiter is used. |
read( buffer-list ) RETURNING
INTEGER |
Reads data from the input. Here buffer-list is a variable list with the
square-brace notation ([param1,param2,...] ).The function returns TRUE if data could be read. |
write( buffer-list
) |
Writes data to the output. Here buffer-list is a variable list with the
square-brace notation ([param1,param2,...] ). |
readLine() RETURNING
STRING |
Reads a line of data from the channel and returns the string. This method must be used if the source stream does not contain lines with field separators. Returns an empty string if the line is empty. Returns NULL when the end of stream is found. |
writeLine( buffer
STRING
) |
Writes a line of data to the channel. This method must be used if the target stream must not contain lines with field separators. |
close() |
Closes the channel. |
One of the following exceptions may occur while using Channels:
Error number | Description |
-6340 | The channel could not be opened for a file. |
-6341 | The required open mode is not supported for a file channel. |
-6342 | The channel could not be opened for a pipe. |
-6343 | The required open mode is not supported for a pipe channel. |
-6344 | Cannot write to an unopened channel. |
-6345 | An error occurred while writing to the channel. |
-6346 | Cannot read from an unopened channel. |
The Channel class is a built-in class that provides basic read/write functionality to access files or to communicate with sub-processes.
First you must declare a base.Channel
variable, then create a
Channel object, and optionally set the field delimiter:
01
DEFINE ch base.Channel02
LET ch = base.Channel.create()03
CALL ch.setDelimiter("^")
You can open a file for reading, writing, or both, by using the openFile()
method:
01
CALL ch.openFile( "file.txt", "w" )
When using "w"
or "a"
modes,
the file is created if it does not exist.
With the openPipe()
method, you can read from the standard
output of a sub-process, write to the standard input, or both.
01
CALL ch.openPipe( "ls", "r" )
When the channel is open, you can read and/or write data from/to the
input/output. You must provide a variable list by using the the square brace
notation ([param1,param2,...]
). The read function returns TRUE
if data could be read.
01
DEFINE a,b INTEGER02
DEFINE c,d CHAR(20)03
WHILE ch1.read([a,b,c,d])04
CALL ch2.write([a,b,c,d])05
END WHILE
You can trap exceptions with the standard WHENEVER ERROR exception handler:
01
WHENEVER ERROR CONTINUE02
CALL ch.write([num,label])03
IF STATUS THEN04
ERROR "An error occurred while reading from channel"05
CALL ch.close()06
RETURN -107
END IF08
WHENEVER ERROR STOP
When you have finished with it, close the channel with the close()
method:
01
CALL ch.close()
A channel is automatically closed when the last reference to the channel object is deleted.
By default, a CR character represents the end of a channel record. If you want to write a CR as part of the line, the string must hold the backslash and CR as two independent characters. This means, that you need to escape the backslash when you write the string constant in the BDL source file.
For example, the following code:
01
CALL ch.write("aaa\\\nbbb") -- Holds one backslash + one CR02
CALL ch.write("ccc\nddd") -- Holds one CR only
... would generate the following output:
01
aaa\02
bbb03
ccc04
ddd
Where line 01 and 02 hold data for the same line in the meaning of a channel record.
When you read these lines back with a channel, you get the following strings in memory:
Read 1
aaa[bs][cr]bbbRead 2
cccRead 3
ddd
These reads would correspond to the following assignments when using string constants:
01
LET s = "aaa\\\nbbb"02
LET s = "ccc"03
LET s = "ddd"
If the stream does not contain
lines with fields (and field separators), you should use the readLine()
and writeLine()
methods. These methods read/write a complete line
from/to the channel, by ignoring the delimiter defined by setDelimiter()
:
01
CALL ch.writeLine("this is a complete line")02
LET buff = ch.readLine()
Line terminators on Windows platforms
On Windows platforms, DOS formatted text files use CR/LF as line terminators. In this section we will describe how you can manage such type of files with the Channel class.
By default, on both Windows and Unix platforms, when reading records from a DOS file with the channel class, the CR/LF line terminator is removed. When writing a record to a file, on Windows, the lines are terminated with CR/LF in the file, while on UNIX, the lines are terminated with LF only.
If you want to avoid the automatic translation of CR/LF, you can use b
option of the openFile()
and openPipe()
methods. You
typically combine the b option with r or w, according
to the read or write operations you want to do:
01
CALL ch.openFile( "mytext.txt", "rb" )
With the b option, when reading lines, on both Windows and UNIX platforms, only LF is removed from CR/LF line terminators. This means, that CR will be copied as a character part of the last field. On the opposite, when writing lines on Windows, LF characters will not be converted to CR/LF. On UNIX, writing lines with or without binary mode does not matter.
This program reads data from the file "file.txt" file that contains 2 columns separated by a | (pipe) character, and re-writes these data at the end of the "fileout.txt" file, separated by "%"
01
MAIN02
DEFINE buff1, buff2 STRING03
DEFINE ch_in, ch_out base.Channel04
LET ch_in = base.Channel.create()05
CALL ch_in.setDelimiter("|")06
LET ch_out = base.Channel.create()07
CALL ch_out.setDelimiter("%")08
CALL ch_in.openFile("file.txt","r")09
CALL ch_out.openFile("fileout.txt","w")10
WHILE ch_in.read([buff1,buff2])11
CALL ch_out.write([buff1,buff2])12
END WHILE13
CALL ch_in.close()14
CALL ch_out.close()15
END MAIN
This program executes the "ls" command and displays the filenames and extensions separately:
01
MAIN02
DEFINE fn CHAR(40)03
DEFINE ex CHAR(10)04
DEFINE ch base.Channel05
LET ch = base.Channel.create()06
CALL ch.setDelimiter(".")07
CALL ch.openPipe("ls -l","r")08
WHILE ch.read([fn,ex])09
DISPLAY fn, " ", ex10
END WHILE11
CALL ch.close()12
END MAIN