Devices are classes that provide read and write access to objects that are usually outside of a process – for example, files. However, you can also access internal objects, such as arrays, as devices.
A device is nothing more than a class with the member function read()
or write()
. A device can be connected with a stream so you can read and write formatted data rather than using the read()
and write()
member functions directly.
boost::iostreams::array_sink
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
#include <iostream>
using namespace boost::iostreams;
int main()
{
char buffer[16];
array_sink sink{buffer};
stream<array_sink> os{sink};
os << "Boost" << std::flush;
std::cout.write(buffer, 5);
}
Example 34.1 uses the device boost::iostreams::array_sink
to write data to an array. The array is passed as a parameter to the constructor. Afterwards, the device is connected with a stream of type boost::iostreams::stream
. A reference to the device is passed to the constructor of boost::iostreams::stream
, and the type of the device is passed as a template parameter to boost::iostreams::stream
.
The example uses the operator operator<<
to write “Boost” to the stream. The stream forwards the data to the device. Because the device is connected to the array, “Boost” is stored in the first five elements of the array. Since the array’s contents are written to standard output, Boost
will be displayed when you run the example.
boost::iostreams::array_source
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
#include <string>
#include <iostream>
using namespace boost::iostreams;
int main()
{
char buffer[16];
array_sink sink{buffer};
stream<array_sink> os{sink};
os << "Boost" << std::endl;
array_source source{buffer};
stream<array_source> is{source};
std::string s;
is >> s;
std::cout << s << '\n';
}
Example 34.2 is based on the previous example. The string written with boost::iostreams::array_sink
to an array is read with boost::iostreams::array_source
.
boost::iostreams::array_source
is used like boost::iostreams::array_sink
. While boost::iostreams::array_sink
supports only write operations, boost::iostreams::array_source
supports only read. boost::iostreams::array
supports both write and read operations.
Please note that boost::iostreams::array_source
and boost::iostreams::array_sink
receive a reference to an array. The array must not be destroyed while the devices are still in use.
boost::iostreams::back_insert_device
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/stream.hpp>
#include <vector>
#include <string>
#include <iostream>
using namespace boost::iostreams;
int main()
{
std::vector<char> v;
back_insert_device<std::vector<char>> sink{v};
stream<back_insert_device<std::vector<char>>> os{sink};
os << "Boost" << std::endl;
array_source source{v.data(), v.size()};
stream<array_source> is{source};
std::string s;
is >> s;
std::cout << s << '\n';
}
Example 34.3 uses a device of type boost::iostreams::back_insert_device
, instead of boost::iostreams::array_sink
. This device can be used to write data to any container that provides the member function insert()
. The device calls this member function to forward data to the container.
The example uses boost::iostreams::back_insert_device
to write “Boost” to a vector. Afterwards, “Boost” is read from boost::iostreams::array_source
. The address of the beginning of the vector and the size are passed as parameters to the constructor of boost::iostreams::array_source
.
Example 34.3 displays Boost
.
boost::iostreams::file_source
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/stream.hpp>
#include <iostream>
using namespace boost::iostreams;
int main()
{
file_source f{"main.cpp"};
if (f.is_open())
{
stream<file_source> is{f};
std::cout << is.rdbuf() << '\n';
f.close();
}
}
Example 34.4 uses the device boost::iostreams::file_source
to read files. While the previously introduced devices don’t provide member functions, boost::iostreams::file_source
provides is_open()
to test whether a file was opened successfully. It also provides the member function close()
to explicitly close a file. You don’t need to call close()
because the destructor of boost::iostreams::file_source
closes a file automatically.
Besides boost::iostreams::file_source
, Boost.IOStreams also provides the device boost::iostreams::mapped_file_source
to load a file partially or completely into memory. boost::iostreams::mapped_file_source
defines a member function data()
to receive a pointer to the respective memory area. That way, data can be randomly accessed in a file without having to read the file sequentially.
For write access to files, Boost.IOStreams provides the devices boost::iostreams::file_sink
and boost::iostreams::mapped_file_sink
.
file_descriptor_source
and file_descriptor_sink
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <iostream>
#include <Windows.h>
using namespace boost::iostreams;
int main()
{
HANDLE handles[2];
if (CreatePipe(&handles[0], &handles[1], nullptr, 0))
{
file_descriptor_source src{handles[0], close_handle};
stream<file_descriptor_source> is{src};
file_descriptor_sink snk{handles[1], close_handle};
stream<file_descriptor_sink> os{snk};
os << "Boost" << std::endl;
std::string s;
std::getline(is, s);
std::cout << s;
}
}
Example 34.5 uses the devices boost::iostreams::file_descriptor_source
and boost::iostreams::file_descriptor_sink
. These devices support read and write operations on platform-specific objects. On Windows these objects are handles, and on POSIX operating systems they are file descriptors.
Example 34.5 calls the Windows function CreatePipe()
to create a pipe. The read and write ends of the pipe are received in the array handles. The read end of the pipe is passed to the device boost::iostreams::file_descriptor_source
, and the write end is passed to the device boost::iostreams::file_descriptor_sink
. Everything written to the stream os, which is connected to the write end, can be read from the stream is, which is connected to the read end. Example 34.5 sends “Boost” through the pipe and to standard output.
The constructors of boost::iostreams::file_descriptor_source
and boost::iostreams::file_descriptor_sink
expect two parameters. The first parameter is a Windows handle or – if the program is run on a POSIX system – a file descriptor. The second parameter must be either boost::iostreams::close_handle or boost::iostreams::never_close_handle. This parameter specifies whether or not the destructor closes the Windows handle or file descriptor.