Input/output library
一、C的IO library是基于stream的,可以说它将stream的概念发扬光大了,C++的I/O library继承了C的IO library,以OOP + TMP的方式对其进行了wrap。
NOTE: 关于wrap,参见
C-and-C++\Wrapper
二、在APUE的《5 Standard I/O Library》中对stream-based I/O进行了非常详细的分析,所以首先阅读APUE的《5 Standard I/O Library》能够帮助理解C++的io library。下面是一些关键性地思想:
三、APUE的《5.2 Streams and FILE Objects》: 描述了stream的概念。
When we open or create a file with the standard I/O library, we say that we have associated a stream with the file.
四、APUE的《5.4 Buffering》
The goal of the buffering provided by the standard I/O library is to use the minimum number of
read
andwrite
calls. (Recall Figure 3.6, which showed the amount of CPU time required to perform I/O using various buffer sizes.) Also, this library tries to do its buffering automatically for each I/O stream, obviating the need for the application to worry about it.
stream-based IO往往是采用buffering策略,c++ IO library也是如此,buffer相关的内容将在Buffer
中进行总结。
cppreference Input/output library
Stream-based I/O
The stream-based input/output library is organized around abstract input/output devices. These abstract devices allow the same code to handle input/output to files, memory streams, or custom adaptor devices that perform arbitrary operations (e.g. compression) on the fly.
NOTE:
1、abstraction的威力
2、stream is a good abstraction
Most of the classes are templated, so they can be adapted to any basic character type. Separate typedefs are provided for the most common basic character types (char
and wchar_t
).
NOTE:
一、上面强调“Most of the classes are templated, so they can be adapted to any basic character type”,那这是否说明C++的Stream-based I/O library只能够是character stream呢?这个问题需要结合character stream和byte stream之间的差异、c++ I/O的实现来谈。
在工程Linux-OS的
Programming\IO\IO-流派\Stream
章节中对“character stream和byte stream之间的差异”进行了总结:byte stream的unit是byte,character stream的unit是character;一个character由一个或者多个byte组成。
二、上面所述的**basic character type**其实包含了:
char
wchar_t
char16_t
char32_t
显然,
char
其实对应的byte,而其它更宽的char类型对应的是character。显然c++的I/O通过抽象CharT
,实现了同时支持**byte stream**、character stream。三、
std::basic_ios
的声明如下:template< class CharT, class Traits = std::char_traits<CharT> > class basic_ios : public std::ios_base
Class hierarchy
The classes are organized into the following hierarchy:
NOTE: 图略,下面是根据原图,使用table的格式组织的
NOTE: 两个正交的概念:
- buffer、input、output
- file、string
下面表格基于上述两个正交的概念进行绘制,它和原文的结构类似,并且还添加了buffer类列。
Abstraction
NOTE: "abstraction"的含义是"基类"、"抽象类"。
注释 | ||
---|---|---|
ios_base | manages formatting flags and input/output exceptions (class) | |
basic_ios | manages an arbitrary stream buffer | The class std::basic_ios provides facilities for interfacing with objects that have std::basic_streambuf interface,显然它为了实现buffering IO的。 |
basic_streambuf | abstracts a raw device (class template) | 这是底层buffer的实现,其它类型的stream的实现都依赖于它,比如 - File I/O implementation的basic_filebuf - String I/O implementation的basic_stringbuf 这些内容将在 Buffer.md 中进行总结 |
basic_ostream | wraps a given abstract device (std::basic_streambuf) and provides high-level output interface | |
basic_istream | wraps a given abstract device (std::basic_streambuf) and provides high-level output interface | |
basic_iostream | wraps a given abstract device (std::basic_streambuf) and provides high-level input/output interface |
File I/O implementation
NOTE: 支持file IO,在前面的"Class hierarchy"章节中,已经对它的implementation class进行了介绍。
Defined in header <fstream>
String I/O implementation
NOTE: 支持string IO,在前面的"Class hierarchy"章节中,已经对它的implementation class进行了介绍。
Defined in header <sstream>
Typedefs
NOTE: 其实就是一堆已经提供好的typedef
Predefined standard stream objects
NOTE: 从下面可以看出在本文开头所总结的观点:
C++的I/O library继承了C的IO library,以OOP + TMP的方式对其进行了wrap
C++ stream object | standard C stream |
---|---|
cin wcin |
standard C input stream stdin |
cout wcout |
standard C output stream stdout |
cerr wcerr |
standard C error stream stderr, unbuffered |
clog wclog |
standard C error stream stderr |
I/O Manipulators
C-style I/O
NOTE: C-style IO也是基于stream的。
C++ IO library and STL
一般我们不将C++ IO library纳入STL的中,但是C++ IO library的设计理念和STL是一脉相承的,并且由于C++ IO library是stream-based的,而stream又非常类似于container,所以C++ std library的设计者已经充分考虑了两者之间的关联,已经实现了让用户按照STL的模式来处理IO stream,连接两者的桥梁是:
1) std::istream_iterator
2) std::ostream_iterator
它们在C++\Library\Standard-library\STL\Iterator-library\Stream-iterators
中进行了详细介绍。
关于本节总结的思想,在geeksforgeeks std::istream_iterator and std::ostream_iterator in C++ STL中进行了较好的论述:
All three components are so designed that they confirm to the principles of data abstraction. Thus any object which holds data and behaves like a container, is a container. Similarly, any iterator which sweeps through the elements in a container is an iterator.
NOTE:
1、duck typing and behavior-based
If an iterator can be used to access elements of a data container, then what about streams? In keeping with the design, Streams too are data containers and so C++ provides us with iterators to iterate over the elements present in any stream. These iterators are called Stream Iterators. To use these iterators the iterator header file must be included.
Bit stream
看了一下,c++的io library是不支持bit stream的,那在c++中如何来处理bit stream呢?
https://sakhnik.com/2018/03/23/bitstream.html
http://www.drdobbs.com/bitstream-parsing-in-c/184402014
Buffer stream
今天写了这样的一个程序
std::pair<void*, size_t> Pack()
{
MsgHeaderType Header;
Header.MsgHead.nSenderID = 1;
Header.MsgHead.nToken = 1;
Header.DataHead.uResponseNumber = 3;
CHSInsFundDataPushField F1;
std::memset(&F1, 0, sizeof(CHSInsFundDataPushField));
F1.ProductIndex = 1;
F1.ProductNo = 1;
std::strcpy(F1.ProductRef, "1");
CHSInsFundDataPushField F2;
std::memset(&F2, 0, sizeof(CHSInsFundDataPushField));
F2.ProductIndex = 2;
F2.ProductNo = 2;
std::strcpy(F2.ProductRef, "2");
CHSInsFundDataPushField F3;
std::memset(&F3, 0, sizeof(CHSInsFundDataPushField));
F3.ProductIndex = 3;
F3.ProductNo = 3;
std::strcpy(F3.ProductRef, "3");
std::size_t size = sizeof(MsgHeaderType) + 3 * sizeof(CHSInsFundDataPushField);
void*Buffer = std::malloc(size);
std::memcpy(Buffer, &Header, sizeof(MsgHeaderType));
std::memcpy((char*) Buffer + sizeof(MsgHeaderType), &F1, sizeof(CHSInsFundDataPushField));
std::memcpy((char*) Buffer + sizeof(MsgHeaderType) + sizeof(CHSInsFundDataPushField), &F2, sizeof(CHSInsFundDataPushField));
std::memcpy((char*) Buffer + sizeof(MsgHeaderType) + sizeof(CHSInsFundDataPushField) * 2, &F3, sizeof(CHSInsFundDataPushField));
return std::pair<void*, size_t> { Buffer, size };
}
这个程序其实非常简单,即将一些struct object输出到一个buffer中,我想的是在c++中有没有更加灵活的方式来实现它?我的第一想法是stream,即我需要一个buffer stream,它可以实现类似于stringstream
的<<
操作,下面是查询到的一些与此相关的内容:
What exactly is streambuf? How do I use it?
另外与此相关的有:c++ byte array,因为我们一般使用byte array来作为buffer。这让我想到了redis的做法,redis为每个client都添加了一个buffer。