赞
踩
C++程序把输入和输出当作字节流,对于面向文本的程序,每个字节对应一个字符。流stream充当程序与流的起点或终点之间的媒介,连接程序端与文件端。文件端可以是文件,也可以是设备,比如键盘和屏幕。
缓存buffer是一块内存,充当程序与设备之间信息交换的临时存储1。一般地,设备,比如硬盘,通常以512字节(或更多)为单位传输信息,而程序每次处理一个字节信息。而且,从内存中读单个字节,比从硬盘中更快。缓存帮助匹配两个不同速率的数据交换:从硬盘中读取一块数据,保存在缓存中,再从缓存中每次读取一个字节,读完后(清空缓存flush the buffer)再从硬盘取一块数据放到缓存;反方向,向缓存每次写入一个字节,写满缓存后再一次性写入硬盘(清空缓存),然后再向缓存写入数据。缓存法比单字节读写法(byte-by-byte)更快和更简单。
在将输入数据传给程序前,缓存法键盘输入允许用户备份和修改输入信息。通常,C++程序在用户按下回车键Enter
时清空输入缓存,当用户输出换行符(newline character)时清空输出缓存,都不必等到缓存填满。
C++提供了多个类来实现和管理流和缓存:
类 class | 描述 |
---|---|
streambuf | 为缓存提供内存,并一同提供用于填充缓存、访问缓存内容、清空缓存和管理缓存内存的类方法。 |
ios_base | 表示流的一般属性,比如是否打开用于读取和是二进制流还是文本流。 |
ios | 基于ios_base class,包括一个指向streambuf对象的指针成员。 |
ostream | 衍生自ios,提供输出方法。 |
istream | 衍生自ios,提供输入方法。 |
iostream | 基于istream和ostream,继承两者的输入和输出方法。 |
在C++程序中包括头文件<iostream>
(在该头文件中声明的对象有外部链接性external linkage和静态生存期static duration2)将自动创建8个流对象(窄字符34个,宽字符44个):
cin
对应标准输入流(standard input stream):默认与标准输入设备(一般是键盘)相关联。cout
对应标准输出流(standard output stream):默认与标准输出设备(一般是显示器)相关联。cerr
对应标准错误流(standard error stream):默认与标准输出设备(一般是显示器)相关联,而且该流不缓存,直接把错误信息发送到屏幕,不等缓存填满或换行符(newline character)。clog
对应标准错误流(standard error stream):默认与标准输出设备(一般是显示器)相关联,而且缓存。C stream | C++ stream | 默认关联设备 | 缓存 |
---|---|---|---|
stdin | cin | 键盘 | 是 |
stdout | cout | 显示器 | 是 |
stderr | cerr | 显示器 | 否 |
— | clog | 显示器 | 是 |
默认cin
与stdin
同步,cout
与stdout
同步。cin
绑定于cout
,意味着在对cin
执行I/O操作之前先清空cout
缓存。而cout
不与任何其他输出流绑定。
#include <istream>
// single character
int get(void); // return character read or EOF if failure
istream & get(char & c); // return invoking object reference
#include <ostream>
// single character
ostream & put(char c); // return invoking object reference
get()
函数有三种模式:单字节模式(见上面代码片段)、C风格字符串模式和流缓存模式。而且字符输入所使用单字节模式也有两种签名:第一种签名与C语言字符输入的gtechar
函数等价,无参数,返回读取的字符,如果出错返回EOF
;第二种签名与put()
函数的一致,将读取的字符赋值给引用参数所指示的char
型变量,返回调用对象引用,所以支持输入级联(concatenation)。
#include <iostream>
using namespace std;
int main(int argc, char const *argv[]) {
char a;
char b;
char c;
cout << "Enter no less than 3 characters: \n";
a = cin.get(); // int get(void)
cin.get(b).get(c); // istream & get(char & c)
cout.put(a).put(b).put(c).put('\n'); // ostream & put(char c)
return 0;
}
输出
Enter no less than 3 characters:
RMB
RMB
#include <istream>
// append '\0' at the end, leave delimiter in queue
istream & get(char * s, streamsize n, char delim='\n');
// append '\0' at the end, discard delimiter
istream & getline(char * s, streamsize n, char delim='\n');
// without checking its content nor appending '\0' at the end
istream & read(char * s, streamsize n);
#include <ostream>
// without checking its content and treat '\0' as regular character
ostream & write(const char * s, streamsize n);
get()
和getline()
读取字符串,直到遇到EOF
、分隔符或者已经读取n-1
个字符,无论哪个先发生。
输入函数 | 默认分隔符 | 处理分隔符 | 结尾无效字符’\0’ |
---|---|---|---|
get | ‘\n’ | 留在队列中 | 添加 |
getline | ‘\n’ | 丢弃 | 添加 |
read | 无 | 无 | 不添加 |
四个函数都是返回调用对象的引用,支持级联。read()
和write()
函数读写一块数据,read()
从输入流中提取n个字符保存在字符数组中,write()
将字符数组中的前n个字符插入到输出流中,都不对内容进行检查,不对无效字符做特殊处理。
#include <iostream> #include <fstream> // file stream #include <cstring> // strlen using namespace std; int main(int argc, char const *argv[]) { ifstream fin("1.txt", ios_base::in); // the same as cin int n = 13; char s1[n]; char s2[n]; char s3[n]; cout << "Enter a string for s1[13]:\n"; // hello, world\n fin.get(s1, n, '\n'); // leave delimiter in queue char a = fin.get(); // delimiter '\n' cout << "strlen(s1): " << strlen(s1); cout.put(a); // newline '\n' cout << s1 << a; cout << "Enter a string for s2[13]:\n"; // hello, world\n fin.getline(s2, n, '\n'); // discard delimiter cout << "strlen(s2): " << strlen(s2) << '\n'; cout << s2 << '\n'; cout << "Enter a string for s3[13]:\n"; // hello, world!!!\n fin.read(s3, n-3); // no appending '\0' at the end cout << "strlen(s3): " << strlen(s3) << '\n'; cout << "output s3 using cout.writer(s3, 13):\n"; cout.write(s3, n) << '\n'; cout << "output s3 using cout << s3 << '\\n':\n"; cout << s3 << '\n'; fin.close(); // close text file return 0; }
文本文件"1.txt"
hello, world
hello, world
hello, world!!!
输出
Enter a string for s1[13]:
strlen(s1): 12
hello, world
Enter a string for s2[13]:
strlen(s2): 12
hello, world
Enter a string for s3[13]:
strlen(s3): 13
output s3 using cout.writer(s3, 13):
hello, wor_<0x04><0x01>
output s3 using cout << s3 << '\n':
hello, wor_<0x04><0x01>
以上代码示例将文本文件"1.txt"与文件输入流对象ifstream fin
相关联,使用fin
读取字符串,与使用标准输入流cin
等价。也可以对cin
重定向,在命令行输入./a.out < 1.txt
,在代码中使用cin
,产生相同效果。
对位移运算符<<
(左移)和>>
(右移)进行重载,得到用于输出cout
的插入insertion运算符和用于输入的提取extraction运算符。提取运算符可以识别字符数组、字符指针和string class
对象三种类型变量,用于保存读取的字符串,而且读取时跳过空白字符。空白字符whitespace character通常包括空格符space、制表符tab和换行符newline三种,更广义的空白字符如下表2,可以用头文件<cctype>
里的int isspace(int c)
函数来检查。插入运算符接收到字符数组名或者字符指针后,利用字符串末尾无效字符决定何时停止显示字符。
字符 | 数值(16进制) | 名称 |
---|---|---|
’ ’ | (0x20) | space (SPC) |
‘\t’ | (0x09) | horizontal tab (TAB) |
‘\n’ | (0x0a) | newline (LF) |
‘\v’ | (0x0b) | vertical tab (VT) |
‘\f’ | (0x0c) | feed (FF) |
‘\r’ | (0x0d) | carriage return (CR) |
清空缓冲的四种情况:
Enter
和换行符'\n'
。cin
绑定于cout
,在对cin
执行I/O操作之前先清空cout
缓存。<ostream>
里的操作符(manipulator,也是函数):flush
(只清空缓存)和endl
(先换行,再清空缓存)。#include <ostream>
ostream & flush(ostream & os);
ostream & endl(ostream & os);
代码示例
#include <iostream> #include <string> // string class using namespace std; int main(int argc, char const *argv[]) { int n = 13; char a[n]; // char array char * b = new char[n]; // char pointer,allocate memory string str; // string class object cin >> a; cin >> b; cin >> str; cout << a << endl; cout << b << '\n' << flush; cout << str; cout.put('\n'); flush(cout); // no '\n', fluch buffer only cout << "hello, world"; endl(cout); // '\n' then flush buffer delete b[]; // free memory return 0; }
输出
good morning, beijing
good
morning,
beijing
hello, world
除了使用提取运算符>>
将字符串保存到string class
对象,还可以使用<string>
里的getline()
函数,从输入流is
中读取一行字符串保存到str
中,默认分隔符是换行符’\n’(提取后丢弃分隔符)。使用string class
的构造函数string(const char * s)
从C风格字符串构造一个等价的string class
对象,相应地使用其成员函数c_str()
返回等价的C风格字符串。另外一个构造函数string(const char * s, size_t n);
可以指明需要拷贝的字符个数。
#include <string>
// get a line from istream into a string object, automatic sizing feature
istream & getline(istream & is, string & str, char delim='\n');
// construct a string object from c-string (null-terminated char sequence)
string(const char * s); // constructor
// construct a string object from buffer, copy the first n chars from array
string(const char * s, size_t n); // constructor
// get c-string equivalent (plus a terminating null character '\0')
const char * c_str() const noexcept;
代码示例
#include <iostream> #include <cstdio> // printf #include <cstring> // strlen using namespace std; int main(int argc, char const *argv[]) { string str1; getline(cin, str1, '!'); cout << str1 << '\n'; cout << "str1.size(): " << str1.size() << '\n'; const char * cstr = str1.c_str(); printf("%s\n", cstr); printf("strlen(cstr): %lu\n", strlen(cstr)); string str2(cstr, strlen(cstr) - 3); cout << str2 << '\n'; return 0; }
输出
hello, world!
hello, world
str1.size(): 12
hello, world
strlen(cstr): 12
hello, wo
<fstream>
衍生自<iostream>
,其中的open()
函数可以创建输入流ifstream
和输出流ofstream
对象,与具体文件相关联,使用方式与标准输入流cin
和标准输出流cout
一样。相应地,使用其成员函数close()
断开文件与文件流对象的连接,而文件流对象和它管理的缓存还在,可以重新使用与其他文件建立连接1。
#include <fstream>
#include <ifstream>
void open(const char * filename, ios_base::openmode mode = ios_base::in);
void open(const string & filename, ios_base::openmode mode = ios_base::in);
#include <ofstream>
void open(const char * filename, ios_base::openmode mode = ios_base::out);
void open(const string & filename, ios_base::openmode mode = ios_base::out);
代码示例
#include <iostream> #include <fstream> #include <string> using namespace std; int main(int argc, char const *argv[]) { ifstream fin; fin.open("1.txt", ifstream::in); ofstream fout("2.txt", ios_base::out); string str; fin >> str; fout << "hey, there\n"; fout << str << '\n'; fin.close(); fout.close(); return 0; }
文本文件"1.txt"
hello, world
文本文件"2.txt"(初始为空)
hey, there
hello,
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。