Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

Stream Library

This library holds classes which are useful for performing streamed input and output. This library is considered safe because it's only the host has the capability of creating a stream bound to some external data source/sink; scripts can only create streams bound to memory. This library also provides streams bound to the standard input, output, and error streams, which are still considered safe.

For interaction with the D host, an InStream corresponds to Tango's InputStream; an OutStream corresponds to Tango's OutputStream; and an InoutStream corresponds to Tango's IConduit. These are the Tango types that underlie the MiniD types, but the MiniD interface is not really the same.

Members

  1. stream.stdin
  2. stream.stdout
  3. stream.stderr
  4. class InStream
    1. this(stream: nativeobj, closable: bool = true)
    2. readXxx()
    3. readString()
    4. readln()
    5. readChars(length: int)
    6. readVector(v: Vector, size: int = #v) or `readVector(type: …
    7. rawRead(size: int, v: Vector = null)
    8. opApply()
    9. skip(distance: int)
    10. seek(pos: int, whence: char)
    11. position([new: int])
    12. size()
    13. close()
    14. isOpen(): bool
  5. class OutStream
    1. this(stream: nativeobj, closable: bool = true)
    2. writeXxx(n)
    3. writeString(s: string)
    4. write(vararg), writeln(vararg)
    5. writef(vararg), writefln(vararg)
    6. writeChars(s: string)
    7. writeJSON(value: table|array, pretty: bool = false)
    8. writeVector(v: Vector, lo: int = 0, hi: int = #v)
    9. flush()
    10. copy(s: InStream|InoutStream)
    11. flushOnNL(b: bool)
    12. seek(pos: int, whence: char)
    13. position([new: int])
    14. size()
    15. close()
    16. isOpen(): bool
  6. class InoutStream
    1. this(conduit: nativeobj, closable: bool = true)
  7. Vector Streams

stream.stdin

An instance of the InStream class bound to the standard input stream (the console).

stream.stdout

An instance of the OutStream class bound to the standard output stream (the console).

stream.stderr

An instance of the OutStream class bound to the standard error stream (on Windows, the console, but on other systems, it can be other things).

class InStream

This is a class which represents a stream of data which can be read.

this(stream: nativeobj, closable: bool = true)

InStream constructor. The stream parameter must be a native object that derives from Tango's InputStream interface. The closable parameter indicates whether or not it is legal to close the corresponding Tango stream object. If true, the close method will work, and when this instance is collected, if the stream has not already been closed, it will do so. If false, the close method will throw an error, and it will not attempt to close the stream when it is collected.

readXxx()

This isn't a single function, but a family of functions. They include readByte, readUByte, readShort, readUShort, readInt, readUInt, readLong, readULong, readFloat, readDouble, readChar, readWChar, and readDChar. They all read one data primitive of the indicated type and return it. readChar reads a single 8-bit UTF-8 code unit, not any more; it won't handle multi-byte encodings. readWChar also only reads one 16-bit UTF-16 code unit. There are no multi-unit encodings in UTF-32, so readDChar will always read a single valid character.

readString()

Reads in a non-human-readable string value. Should only be used as an opposite to OutStream.writeString. See its documentation for more info.

readln()

Reads a line of text followed by a line-end. The line-end is not included in the returned string. Throws an error if you try to read past the end of the stream.

readChars(length: int)

Reads the given number of UTF-8 characters and returns them as a string.

readVector(v: Vector, size: int = #v) or readVector(type: string, size: int)

This function reads data from the file into an instance of Vector. There are two different ways to call it. If you call it the first way, passing a vector, it will attempt to read size elements from the file into the vector. If size is not the same as the length of the vector that is passed in, the vector will be resized. The second way to call this function is to give it a type (the same type codes that are used when creating a vector) and a size, which is how many elements are to be read. In this case, this function will allocate a new Vector instance, fill it with the data, and return it.

rawRead(size: int, v: Vector = null)

Similar to readVector, this function will attempt to read at most size bytes into a Vector, but unlike readVector, it will never throw an exception for an end-of-flow condition. It returns the read vector. If you don't pass anything for v, it will create a new Vector(u8) instance itself. If you do pass a Vector for v, it must be an i8 or u8 vector. In either case, the returned vector's size will be set to how many bytes were actually read, up to at most size. If the length of the returned vector is 0, it means there is no more data in the stream.

opApply()

This is an iterator bootstrap for iterating over all the lines in the given stream. The data in the stream must be text data with line-ends for this to work properly. This gives two values for the foreach indices; the first is the current line number (line numbering starts with 1), and the second is the current line as a string. This stops when the end of the stream is reached.

skip(distance: int)

Skip distance bytes forward. The stream does not have to be seekable for this method.

seek(pos: int, whence: char)

If possible, moves the stream cursor to a new position in bytes. pos is the integer position, which means different things based on whence. If whence is 'b', pos is an offset from the beginning of the stream. If whence is 'c', then pos is a signed offset from the current position in the stream (you can jump back, using negative numbers, as well as forward). And if whence is 'e', pos is a negative offset from the end of the stream. Not all streams are seekable; unseekable streams will throw an error if you use this function on them.

position([new: int])

The stream must be seekable to call this method. If called with no parameters, gets the stream's current cursor position, in bytes, from the beginning of the stream. If called with a parameter, it's the same as performing a seek(new, 'b') - that is, it sets the stream's cursor position to the offset, in bytes, from the beginning of the stream.

size()

The stream must be seekable to call this method. Gets the total size, in bytes, of the underlying stream. This is not a lightweight function, so don't call it a lot (i.e. in a loop).

close()

Close the stream. If the stream was not created as closable (see this), this throws an error. For instance, the streams bound to the console are not closable. Once a stream has been closed, most methods will throw an error if called on it.

isOpen(): bool

Returns whether or not the stream is open. If the close method was called successfully on it, this will then return true.

class OutStream

This is a class which represents a stream of data which can be written. All methods of this class return a "chaining reference", that is, the instance on which they were called. This way, you can write code like "output.writeInt(a).writeInt(b).writeInt(c)".

this(stream: nativeobj, closable: bool = true)

OutStream constructor. The stream parameter must be a native object that derives from Tango's OutputStream interface. The closable parameter indicates whether or not it is legal to close the corresponding Tango stream object. If true, the close method will work, and when this instance is collected, if the stream has not already been closed, it will do so (it will also flush it before closing). If false, the close method will throw an error, and it will not attempt to close the stream when it is collected.

writeXxx(n)

Like the readXxx functions in InStream, this is not a single function, but a family of functions, including writeByte, writeUByte, writeShort, writeUShort, writeInt, writeUInt, writeLong, writeULong, writeFloat, writeDouble, writeChar, writeWChar, and writeDChar. Each writes one data primitive of the indicated type, as the opposite of the InStream read functions.

writeString(s: string)

Writes out a string in a raw format (not meant to be read by humans). Basically this consists of the string's length in bytes as a platform-dependent length (32- or 64-bit integer) followed by its UTF-8 encoding. If you need something more cross-platform, consider the readChars and writeChars functions instead. The written-out string should only be read back in with InStream.readString.

write(vararg), writeln(vararg)

These work like the baselib write and writeln functions. Writes an unformatted UTF-8 string to the file. writeln() is the same as write(), except it writes a system-dependent line-end after writing its parameters.

writef(vararg), writefln(vararg)

These work like the baselib writef and writefln functions. Writes a formatted UTF-8 string to the file. writefln() is the same as writef(), except it writes a system-dependent line-end after writing its parameters.

writeChars(s: string)

Writes the given string as a sequence of UTF-8 characters, with no length or line-end.

writeJSON(value: table|array, pretty: bool = false)

Writes formatted JSON data to the output stream. See the baselib documentation of toJSON for more info. This is more efficient than using toJSON and then writing the result as no temporary string is created; the data is written right to the stream as it's generated.

writeVector(v: Vector, lo: int = 0, hi: int = #v)

Writes data from a vector to the stream. If you just pass a vector, it will write all the vector's data out. You can optionally specify low and high indices to only write a slice of the vector. These indices work like normal slice indices. Nothing like a size or type code is written out; just the raw data from the vector.

flush()

Flushes the stream. This will empty the output buffer into the destination medium.

copy(s: InStream|InoutStream)

Reads all the data from the given InStream or InoutStream and writes it out. This is a very fast way to copy data from one stream to another.

flushOnNL(b: bool)

Sets whether the stream will be automatically flushed on newlines output by writeln and writefln calls. Newlines embedded in the middle of output or output by other methods do not affect the auto-flush behavior.

seek(pos: int, whence: char)

If possible, moves the stream cursor to a new position in bytes. pos is the integer position, which means different things based on whence. If whence is 'b', pos is an offset from the beginning of the stream. If whence is 'c', then pos is a signed offset from the current position in the stream (you can jump back, using negative numbers, as well as forward). And if whence is 'e', pos is a negative offset from the end of the stream. Not all streams are seekable; unseekable streams will throw an error if you use this function on them.

position([new: int])

The stream must be seekable to call this method. If called with no parameters, gets the stream's current cursor position, in bytes, from the beginning of the stream. If called with a parameter, it's the same as performing a seek(new, 'b') - that is, it sets the stream's cursor position to the offset, in bytes, from the beginning of the stream.

size()

The stream must be seekable to call this method. Gets the total size, in bytes, of the underlying stream. This is not a lightweight function, so don't call it a lot (i.e. in a loop).

close()

Close the stream. If the stream was not created as closable (see this), this throws an error. For instance, the streams bound to the console are not closable. Once a stream has been closed, most methods will throw an error if called on it.

isOpen(): bool

Returns whether or not the stream is open. If the close method was called successfully on it, this will then return true.

class InoutStream

This is a class which represents a stream of data which can be read and written. InoutStream has all the methods of both InputStream and OutputStream, so anything that's legal to do to either of those is legal to do on this class as well. As such, only the functions which are unique to Stream are documented here. All the methods that are common to OutStream and InoutStream return a chaining reference.

Something extra that InoutStream does for you is that it maintains data coherence. What does this mean? Consider the case where you have a file opened for reading and writing. You write some data to it, then you seek back and read it back out. (This is kind of contrived, but just bear with me here.) However, the IO library might use buffering to improve performance. When you write data, it might not be written immediately. So if you were to write some data to the file and then read it back in immediately, you might not get back what you wrote out. The data is incoherent - what is in the buffer does not match what's in the actual file.

InoutStream handles this by keeping a "dirty" flag. Whenever you write data to a InoutStream through its methods, it sets the dirty flag. Whenever you try to read or seek, if the dirty flag is set, it flushes the output buffer and clears the input buffer. This is completely invisible to the user.

this(conduit: nativeobj, closable: bool = true)

InoutStream constructor. This takes a single native object parameter, conduit, which must derive from Tango's IConduit interface. It may or may not be seekable. The closable params means the same thing as in the InStream and OutStream constructors.

Vector Streams

In addition to the generic stream classes above, there are also three classes which wrap Vector objects: VectorInStream, VectorOutStream, and VectorInoutStream. You can use the Vector stream classes to read and write streamed data directly in memory. They all behave more or less the same, so I'll just document them together.

All three types are constructed the same way: they take a single Vector which is to be wrapped. The Vector can be of any type. All three kinds of streams are seekable. Those that support output (VectorOutStream and VectorInoutStream will automatically expand the underlying Vector to accommodate data when the end of the Vector's buffer is reached. The Vector's length will be extended just enough to hold the written data, even if the Vector's item size is larger than 1. No matter what type the underlying Vector is, however, the stream's position will always be reported in bytes, as with any other stream.

Here's a small example of using a VectorInoutStream:

import stream: VectorInoutStream

local v = Vector.fromArray("u32", [1, 2, 3])
local s = VectorInoutStream(v)

writeln(s.size()) // prints 12
writeln(s.readUInt()) // prints 1
s.seek(0, 'e') // seek to end
s.writeUInt(4) // writing past the end of the vector - will resize
writeln(v) // prints [1, 2, 3, 4], cool