module Netchannels:sig
..end
Object-oriented I/O: Basic types and classes
Contents
The tutorial has been moved to Netchannels_tut
.
There are three levels of class types for channels:
rec_in_channel
and rec_out_channel
: Primitive, but standardized levelraw_in_channel
and raw_out_channel
: Unix levelin_obj_channel
and out_obj_channel
: Application levelThe "rec" level has been recently introduced to improve interoperability with other libraries (e.g. camomile). The idea is to standardize the real core methods of I/O, so they have the same meaning in all libraries. Read "Basic I/O class types" for more.
The "raw" level represents the level of Unix file descriptors.
The application level is what should be used in programs. In addition
to the "raw" level one can find a number of convenience methods,
e.g. input_line
to read a line from the channel. The downside is that
these methods usually work only for blocking I/O.
One can lower the level by coercion, e.g. to turn an in_obj_channel
into a rec_in_channel
, apply the function
(fun ch -> (ch : in_obj_channel :> rec_in_channel))
To higher the level, apply lift_in
or lift_out
, defined below.
Interface changes: Since ocamlnet-0.98, the semantics of
the methods input
and output
has slightly changed. When the end
of the channel is reached, input
raises now End_of_file
. In previous
releases of ocamlnet, the value 0 was returned. When the channel cannot
process data, but is in non-blocking mode, both methods now return the
value 0. In previous releases of ocamlnet, the behaviour was not
defined.
Ocamlnet-3.0 changed the behavior of close_out
. Errors are no longer
reported - instead, the exception is logged to Netlog
. For a stricter
error handling, it is suggested to call flush
first. Also, close_in
and close_out
no longer raise Closed_channel
when the channel is
already closed. Read more about this in the section
How to close channels in case of errors.
exception Closed_channel
Raised when channel operations are called when the channel is closed
exception Buffer_underrun
Raised by input methods if the internal buffer of the channel is too empty to read even one byte of data. This exception is only used by certain implementations of channel classes.
exception Command_failure of Unix.process_status
Raised by close_in
or close_out
if the channel is connected with
another process, and the execution of that process fails.
class type rec_in_channel =object
..end
Recommended input class type for library interoperability.
class type raw_in_channel =object
..end
Basic Unix-level class type for input channels as used by ocamlnet.
class type rec_out_channel =object
..end
Recommended output class type for library interoperability.
class type raw_out_channel =object
..end
Basic Unix-level class type for output channels as used by ocamlnet.
class type raw_io_channel =object
..end
A channel supporting both input and output.
class type compl_in_channel =object
..end
Further methods usually supported by ocamlnet channel implementations.
class type in_obj_channel =object
..end
The application-level input channel supports raw and complemented methods
class type compl_out_channel =object
..end
Further methods usually supported by ocamlnet channel implementations.
class type out_obj_channel =object
..end
The application-level output channel supports raw and complemented methods
class type io_obj_channel =object
..end
A channel supporting both input and output.
class type trans_out_obj_channel =object
..end
A transactional output channel has a buffer for uncommitted data.
class input_channel :?onclose:unit -> unit -> Stdlib.in_channel ->
in_obj_channel
Creates an input channel from an in_channel
, which must be open.
val input_channel : ?onclose:(unit -> unit) -> Stdlib.in_channel -> in_obj_channel
Same as function
class input_command :string ->
in_obj_channel
Runs the command with /bin/sh
, and reads the data the command prints
to stdout.
val input_command : string -> in_obj_channel
Same as function
class input_string :?pos:int -> ?len:int -> string ->
in_obj_channel
Creates an input channel from a (constant) string.
val input_string : ?pos:int -> ?len:int -> string -> in_obj_channel
Same as function
class input_bytes :?pos:int -> ?len:int -> Stdlib.Bytes.t ->
in_obj_channel
Same for constant bytes
val input_bytes : ?pos:int -> ?len:int -> Stdlib.Bytes.t -> in_obj_channel
Same as function
class input_memory :?pos:int -> ?len:int -> Netsys_types.memory ->
in_obj_channel
Same for constant memory
val input_memory : ?pos:int -> ?len:int -> Netsys_types.memory -> in_obj_channel
Same as function
val input_tstring : ?pos:int -> ?len:int -> Netsys_types.tstring -> in_obj_channel
Same for tagged strings (only as function)
val create_input_netbuffer : ?keep_data:bool -> Netbuffer.t -> in_obj_channel * (unit -> unit)
Creates an input channel and a shutdown function for a netbuffer. This is a destructive implementation: Every time data is read, the octets are taken from the beginning of the netbuffer, and they are deleted from the netbuffer (recall that a netbuffer works like a queue of characters).
Conversely, the user of this class may add new data to the netbuffer at any time. When the shutdown function is called, the EOF condition is recorded, and no further data must be added.
If the netbuffer becomes empty, the input methods raise Buffer_underrun
when the EOF condition has not yet been set, and they raise
End_of_file
when the EOF condition has been recorded.
keep_data
: do not delete read data from the buffer
val lexbuf_of_in_obj_channel : in_obj_channel -> Stdlib.Lexing.lexbuf
Creates a lexical buffer from an input channel. The input channel is not closed when the end is reached
This function does not work for non-blocking channels.
val string_of_in_obj_channel : in_obj_channel -> string
Reads from the input channel until EOF and returns the characters as string. The input channel is not closed.
This function does not work for non-blocking channels.
val bytes_of_in_obj_channel : in_obj_channel -> Stdlib.Bytes.t
Same for bytes
val lines_of_in_obj_channel : in_obj_channel -> string list
Reads from the input channel until EOF and returns the lines as string list. The input channel is not closed.
This function does not work for non-blocking channels.
val with_in_obj_channel : (#in_obj_channel as 'a) -> ('a -> 'b) -> 'b
with_in_obj_channel ch f
:
Computes f ch
and closes ch
. If an exception happens, the channel is
closed, too.
class output_channel :?onclose:unit -> unit -> Stdlib.out_channel ->
out_obj_channel
Creates an output channel writing into an out_channel
.
class output_command :?onclose:unit -> unit -> string ->
out_obj_channel
Runs the command with /bin/sh
, and data written to the channel is
piped to stdin of the command.
class output_buffer :?onclose:unit -> unit -> Stdlib.Buffer.t ->
out_obj_channel
This output channel writes the data into the passed buffer.
class output_netbuffer :?onclose:unit -> unit -> Netbuffer.t ->
out_obj_channel
This output channel writes the data into the passed netbuffer.
class output_null :?onclose:unit -> unit -> unit ->
out_obj_channel
This output channel discards all written data.
val with_out_obj_channel : (#out_obj_channel as 'a) -> ('a -> 'b) -> 'b
with_out_obj_channel ch f
:
Computes f ch
and closes ch
. If an exception happens, the channel is
closed, too.
Delegation classes just forward method calls to an parameter
object, i.e. when method m
of the delegation class is called,
the definition of m
is just to call the method with the same
name m
of the parameter object. This is very useful in order
to redefine methods individually.
For example, to redefine the method pos_in
of an in_obj_channel
,
use
class my_channel = object(self)
inherit in_obj_channel_delegation ...
method pos_in = ...
end
As a special feature, the following delegation classes can suppress
the delegation of close_in
or close_out
, whatever applies.
Just pass close:false
to get this effect, e.g.
class input_channel_don't_close c =
in_obj_channel_delegation ~close:false (new input_channel c)
This class does not close c : in_channel
when the close_in
method is called.
class rec_in_channel_delegation :?close:bool -> rec_in_channel ->
rec_in_channel
class raw_in_channel_delegation :?close:bool -> raw_in_channel ->
raw_in_channel
class in_obj_channel_delegation :?close:bool -> in_obj_channel ->
in_obj_channel
class rec_out_channel_delegation :?close:bool -> rec_out_channel ->
rec_out_channel
class raw_out_channel_delegation :?close:bool -> raw_out_channel ->
raw_out_channel
class out_obj_channel_delegation :?close:bool -> out_obj_channel ->
out_obj_channel
The following classes and functions add missing methods to reach
a higher level in the hierarchy of channel class types. For most
uses, the lift_in
and lift_out
functions work best.
val lift_in : ?eol:string list ->
?buffered:bool ->
?buffer_size:int ->
?pass_through:int ->
[ `Raw of raw_in_channel | `Rec of rec_in_channel ] ->
in_obj_channel
Turns a rec_in_channel
or raw_in_channel
, depending on the passed
variant, into a full in_obj_channel
object. (This is a convenience
function, you can also use the classes below directly.) If you
want to define a class for the lifted object, use
class lifted_ch ... =
in_obj_channel_delegation (lift_in ...)
eol
: The accepted end-of-line delimiters. The method
input_line
recognizes any of the passed strings as EOL
delimiters. When more than one delimiter matches, the longest
is taken. Defaults to ["\n"]
. The default cannot be
changed when buffered=false
(would raise Invalid_argument
).
The delimiter strings must neither be empty, nor longer than
buffer_size
.buffered
: Whether a buffer is added, by default truebuffer_size
: The size of the buffer, if any, by default 4096pass_through
: If the read request has at least this size,
and the buffer is currently empty, the buffer will be bypassed.
Defaults to max_int
, i.e. it is off.val lift_out : ?buffered:bool ->
?buffer_size:int ->
?pass_through:int ->
[ `Raw of raw_out_channel | `Rec of rec_out_channel ] ->
out_obj_channel
Turns a rec_out_channel
or raw_out_channel
, depending on the passed
variant, into a full out_obj_channel
object. (This is a convenience
function, you can also use the classes below directly.) If you
want to define a class for the lifted object, use
class lifted_ch ... =
out_obj_channel_delegation (lift_out ...)
buffered
: Whether a buffer is added, by default truebuffer_size
: The size of the buffer, if any, by default 4096pass_through
: If the write request has at least this size,
and the buffer is currently empty, the buffer will be bypassed.
Defaults to max_int
, i.e. it is off.class virtual augment_raw_in_channel :object
..end
This class implements the methods from compl_in_channel
by calling
the methods of raw_in_channel
.
class lift_rec_in_channel :?start_pos_in:int -> rec_in_channel ->
in_obj_channel
This class implements pos_in
and the methods from compl_in_channel
by calling the methods of rec_in_channel
.
class virtual augment_raw_out_channel :object
..end
This class implements the methods from compl_out_channel
by calling
the methods of raw_out_channel
.
class lift_raw_out_channel :raw_out_channel ->
out_obj_channel
This class implements the methods from compl_out_channel
by calling
the methods of raw_out_channel
.
class lift_rec_out_channel :?start_pos_out:int -> rec_out_channel ->
out_obj_channel
This class implements pos_out
and the methods from compl_out_channel
by calling the methods of rec_out_channel
.
typeinput_result =
[ `Data of int | `Separator of string ]
This type is for the method enhanced_input
of enhanced_raw_in_channel
.
`Data n
means that n
bytes have been copied to the target string`Separator s
means that no bytes have been copied, but that an
end-of-line separator s
has been foundclass type enhanced_raw_in_channel =object
..end
Defines private methods reading text line by line
class buffered_raw_in_channel :?eol:string list -> ?buffer_size:int -> ?pass_through:int -> raw_in_channel ->
enhanced_raw_in_channel
This class adds a buffer to the underlying raw_in_channel
.
class buffered_raw_out_channel :?buffer_size:int -> ?pass_through:int -> raw_out_channel ->
raw_out_channel
This class adds a buffer to the underlying raw_out_channel
.
class input_descr :?blocking:bool -> ?start_pos_in:int -> ?fd_style:Netsys.fd_style -> Unix.file_descr ->
raw_in_channel
Creates a raw_in_channel
for the passed file descriptor, which must
be open for reading.
class output_descr :?blocking:bool -> ?start_pos_out:int -> ?fd_style:Netsys.fd_style -> Unix.file_descr ->
raw_out_channel
Creates a raw_out_channel
for the passed file descriptor, which must
be open for writing.
class socket_descr :?blocking:bool -> ?start_pos_in:int -> ?start_pos_out:int -> ?fd_style:Netsys.fd_style -> Unix.file_descr ->
raw_io_channel
Creates a raw_io_channel
for the passed socket descriptor, which must
be open for reading and writing, and not yet shut down in either
direction.
typeclose_mode =
[ `Commit | `Rollback ]
Whether a close_out
implies a commit or rollback operation
class buffered_trans_channel :?close_mode:close_mode -> out_obj_channel ->
trans_out_obj_channel
A transactional output channel with a transaction buffer implemented in memory
val make_temporary_file : ?mode:int ->
?limit:int ->
?tmp_directory:string ->
?tmp_prefix:string -> unit -> string * Stdlib.in_channel * Stdlib.out_channel
Creates a temporary file in the directory tmp_directory
with a name
prefix tmp_prefix
and a unique suffix. The function returns
the triple (name, inch, outch) containing the file name
,
the file opened as in_channel inch
and as out_channel outch
.
mode
: The creation mask of the file; defaults to 0o600, i.e. the
file is private for the current userlimit
: Limits the number of trials to find the unique suffix.
Defaults to 1000.tmp_directory
: Defaults to Netsys_tmp.tmp_directory()
tmp_prefix
: By default "netstring"
. This needs not to be
unique, but just descriptive.class tempfile_trans_channel :?close_mode:close_mode -> ?tmp_directory:string -> ?tmp_prefix:string -> out_obj_channel ->
trans_out_obj_channel
A transactional output channel with a transaction buffer implemented as temporary file
Note that this has nothing to do with "pipes" on the Unix level. It is, however, the same idea: Connecting two I/O resources with an intermediate buffer.
class pipe :?conv:Netbuffer.t -> bool -> Netbuffer.t -> unit -> ?buffer_size:int -> unit ->
io_obj_channel
A pipe
has two internal buffers (realized by Netbuffer).
class output_filter :io_obj_channel -> out_obj_channel ->
out_obj_channel
An output_filter
filters the data written to it through the
io_obj_channel
(usually a pipe
), and writes the filtered data
to the passed out_obj_channel
.
class input_filter :in_obj_channel -> io_obj_channel ->
in_obj_channel
An input_filter
filters the data read from it through the
io_obj_channel
(usually a pipe
after the data have been
retrieved from the passed in_obj_channel
.
If you have the choice, prefer output_filter
over input_filter
.
The latter is slower.
The primary application of filters is to encode or decode a channel on the fly. For example, the following lines write a BASE64-encoded file:
let ch = new output_channel (open_out "file.b64") in
let encoder = new Netencoding.Base64.encoding_pipe ~linelength:76 () in
let ch' = new output_filter encoder ch in
... (* write to ch' *)
ch' # close_out();
ch # close_out(); (* you must close both channels! *)
All bytes written to ch'
are BASE64-encoded and the encoded bytes are
written to ch
.
There are also pipes to decode BASE64, and to encode and decode the "Quoted printable" format. Encoding and decoding work even if the data is delivered in disadvantageous chunks, because the data is "re-chunked" if needed. For example, BASE64 would require that data arrive in multiples of three bytes, and to cope with that, the BASE64 pipe only processes the prefix of the input buffer that is a multiple of three, and defers the encoding of the extra bytes till the next opportunity.