你们自用服务器都买什么硬盘?

买了个 HP gen8 还在路上,先来取取经,

打算放到家里放点数据,跑点小服务,简单的数据分析啥的,

不打算当 NAS 用,所以对硬盘大小需求不大,但是数据还是尽可能保证安全*好了,

整个预算也不高,是买个相对靠谱点 10k , 15k 服务器硬盘就行了还是买个普通点的 NAS 硬盘 raid 一下,

求科普。

NAS 硬盘 普通点 取取18 条回复 • 2016-12-15 10:52:20 +08:00
xspoco 1
xspoco 2016-11-06 00:16:25 +08:00
红盘 黑盘 组 raid 吧
yangxin0 2
yangxin0 2016-11-06 00:23:06 +08:00 via iPhone
红盘 raid1
Mac 3
Mac 2016-11-06 00:25:54 +08:00
黑盘
kokutou 4
kokutou 2016-11-06 00:34:48 +08:00 via Android
我是不重要数据两块 ST2000DM001 组的 raid0 。。。。
debuge 5
debuge 2016-11-06 07:23:55 +08:00 via Android
不知道是不是馊主意,个人觉得硬盘的可靠性已经比较高了,所以主要考虑价格、速度和噪音,如果数据不是很重要, raid 也不是必须的,上云盘同步,个人使用应该是妥妥的了。
当然,如果是商业应用,怎么稳妥怎么来。
strahe 6
strahe 2016-11-06 13:40:12 +08:00
@debuge 是个馊主意,看了下 7.2K 的企业版也不是很贵了,还是 raid 吧
loadinger 7
loadinger 2016-11-13 23:36:26 +08:00 via Android
cu 的 gen8 吗?我跟你同一天买的…你的到了吗?我还是法兰克福已封发…
strahe 8
strahe 2016-11-14 13:00:44 +08:00
@loadinger 我也没到 法兰克福已封发
loadinger 9
loadinger 2016-11-14 13:12:36 +08:00
@strahe 那我也就放心了…. [邪恶]
strahe 10
strahe 2016-11-14 14:00:06 +08:00
@loadinger 刚才看了下 早上已经到杭州了

loadinger 11
loadinger 2016-11-15 09:34:13 +08:00 via Android
@strahe 果然长沙还是我不行啊…还是老状态…
ideaplat 12
ideaplat 2016-11-19 08:35:19 +08:00 via Android
@strahe 我的还没出发,买的 dell t20
Hardrain 13
Hardrain 2016-12-03 18:51:20 +08:00
WD Red
loadinger 14
loadinger 2016-12-09 13:56:16 +08:00
楼主*后什么方案? 我 wd red 4t * 2 了.
strahe 15
strahe 2016-12-12 09:55:24 +08:00
@loadinger 我两个希捷盘 2t*2 raid1

https://item.jd.com/929438.html
loadinger 16
loadinger 2016-12-13 09:17:05 +08:00
@strahe 你装的什么系统啊. 我自己装的 debian .但是 hpe 的 监控系统不会装.也无法确定硬盘休眠.. 虽然很多人说这玩艺就是 7*24 的..
strahe 17
strahe 2016-12-13 14:38:00 +08:00
@loadinger 我也是 debian , 据说没用 gen8 的 raid 卡都系统无法确定硬盘休眠,我现在基本不使用 hpe 的功能,配置都是基于系统级别的,我是 24*7
loadinger 18
loadinger 2016-12-15 10:52:20 +08:00
@strahe 哈哈.那要握个爪了…. 难得能碰到装 debian 的..
2*4T 无 raid, 另外用了一个单盘 raid 装的系统. 之前我把系统装在了 sd 卡上,后来觉得不太合适就重装到现在 的单盘 raid 了. 因为 如果不 raid 装系统的时候都不能选中第三个 sata 口… 现在情况是 4T -> 1#sata 4T->2#sata 200G(OS) -> 3# 单盘 raid…这样的.
不知道你怎么装的系统…

新手建站求助, tomcat 跑 JAVA Web,预计同时在线人数约 50 人。服务器需要买怎么样的配置?

需求:同时在线人数大约 50 人,并发量应该可以当作 200 以内吧;流畅运行 tomcat ;访问速度快,请求延迟几十毫秒内。

请教配置应该购买怎么样的呢?

目前看中阿里云,双核,8G , 5Mbps 宽带。请问够用吗?

tomcat 人数 Java 在线10 条回复 • 2016-12-08 14:48:23 +08:00
lookst 1
lookst 2016-12-08 09:18:22 +08:00
大神们除了阿里云,有其他推荐吗?
xuhaoyangx 2
xuhaoyangx 2016-12-08 09:25:42 +08:00
什么 java web
ytmsdy 3
ytmsdy 2016-12-08 09:32:16 +08:00
1 核 2G , 5Mbps 就够了。。主要是带宽
miaomiaoweiwei 4
miaomiaoweiwei 2016-12-08 09:59:13 +08:00
要看你业务是什么吧?你 50 人在线,在线做什么?运算很多?还是每个人的内存使用很多?就 50 人在线,你就想保持 50 个 web socket 的话,那 1 核 2G 妥妥的。关键看你干啥。
wangzhangwei 5
wangzhangwei 2016-12-08 10:11:34 +08:00
跟业务有关系,一般的网站、论坛 1C2G 5M *对够用。
qcloud 6
qcloud 2016-12-08 10:14:00 +08:00 via iPhone
@lookst 试试腾讯云吧
MajorAdam 7
MajorAdam 2016-12-08 10:21:05 +08:00 via Android
低配够用
duolai798 8
duolai798 2016-12-08 10:26:57 +08:00
单核 4G5M 就够了,其实你可以先买一个月试试,配置不够再临时升级就完了。如果把静态资源 CDN 化,带宽可能都用不上 5M 。
spLite 9
spLite 2016-12-08 10:51:04 +08:00
看你跑什么业务了,我的没多少图片、音频, 1c 1g 1m…
Guladong 10
Guladong 2016-12-08 14:48:23 +08:00
利益相关,我是睿江云销售,你是正规网站吗?是的话可以在我这买一天测试看吧

想自购个服务器搭建校内影院网站 求指导

如题 请问我需要注意什么 没有这方面的经验 以及服务器要求什么 还有环境之类的 谢谢
服务器 校内 请问 影院16 条回复 • 2017-04-25 10:56:14 +08:00
beimenjun 1
beimenjun 2016-11-18 20:04:03 +08:00
稍微大的学校应该都有类似的吧?楼主说说学校情况?如果有轮子就不要造了。
ErnieSauce 2
ErnieSauce 2016-11-18 20:05:40 +08:00 via iPhone
@beimenjun 轮子是指什么 我对这方面不太懂 我们学校没做这个 我现在管理一个机房 有网线之类的 想要搞一个影院
zouxy 3
zouxy 2016-11-18 20:26:31 +08:00
有网线之类的 ….
ErnieSauce 4
ErnieSauce 2016-11-18 20:31:52 +08:00 via iPhone
@zouxy 咳咳 不太懂 能不能给点解决方案
newworld 5
newworld 2016-11-18 20:36:05 +08:00 via iPhone
既然自己管理机房,只要本校内部用,那就简单多了。。。
ErnieSauce 6
ErnieSauce 2016-11-18 20:50:18 +08:00 via iPhone
@newworld 怎么简单 我需要什么样的服务器之类的求推荐
loading 7
loading 2016-11-18 21:02:06 +08:00 via Android
先说预算!
ys0290 8
ys0290 2016-11-18 21:14:18 +08:00 via iPhone
先说版权
Marfal 9
Marfal 2016-11-18 21:17:22 +08:00
@ys0290 内部使用“不存在”版权问题
shoaly 10
shoaly 2016-11-18 21:38:53 +08:00
内部的话 不用搭建电影服务器, 搭建一个种子服务器就可以了, 局域网的种子 下载速度快的飞起, 我以前的大学就是

lovedeluo 11
lovedeluo 2016-11-19 00:43:41 +08:00
每个大学都有自己的 BT 站点吧,不过注意搞好和目前比较火的相关站点关系。我们学校的 BT 站就被一个校外站举报搞过。
xspoco 12
xspoco 2016-11-19 04:17:40 +08:00
需要在线播放?
jessun1990 13
jessun1990 2016-11-19 08:32:19 +08:00 via iPhone
是否需要在线播放?
如果不需要,做一个提供影片信息和种子(下载地址)的网站。
如果使用流媒体在线播放,本人个人使用过的方案是“先锋影音”,注意时刻监控服务器承受能力。
个人建议:电影资源网站实在太多,建议只做经典和高分电影,???烂片看了简直浪费生命。
ErnieSauce 14
ErnieSauce 2016-11-19 09:23:24 +08:00 via iPhone
@ys0290 内网版权监管严格吗
ErnieSauce 15
ErnieSauce 2016-11-19 09:23:58 +08:00 via iPhone
@xspoco 需要在线播放的
zhengxiaowai 16
zhengxiaowai 2017-04-25 10:56:14 +08:00
找你学校的计算机中心老师。。帮你要一个虚拟机来。。。

以前学校超算中心,速度快,性能强。。爽歪歪

lnmp 中安装的 wordpress,居然不能上传图片了

显示: The uploaded file could not be moved to wp-content/uploads/2016/12.

运行: ps -ef|grep php-fpm , 结果为: root 5653 1 0 01:22 ? 00:00:00 php-fpm: master process (/etc/php-fpm.conf) apache 5655 5653 0 01:22 ? 00:00:00 php-fpm: pool www apache 5656 5653 0 01:22 ? 00:00:00 php-fpm: pool www apache 5657 5653 0 01:22 ? 00:00:00 php-fpm: pool www apache 5658 5653 0 01:22 ? 00:00:00 php-fpm: pool www apache 5659 5653 0 01:22 ? 00:00:00 php-fpm: pool www ec2-user 5687 5528 0 01:23 pts/0 00:00:00 grep –color=auto php-fpm

已经修改了 sudo vi /etc/php-fpm.d/www.conf 中的 user 和 group 都是 nginx ,重启 php-fpm 和 nginx ,结果居然没改变。 到底怎么回事啊? 都快晕了。

10 条回复    2017-01-03 15:25:49 +08:00
onlyhot
    1

onlyhot   2017-01-03 09:38:41 +08:00 via iPhone

*反应就是目录权限
joeke
    2

joeke   2017-01-03 09:40:13 +08:00

把文件的权限和所属主 也改一下
RobertYang
    3

RobertYang   2017-01-03 09:51:00 +08:00 via Android

beiping96
    4

beiping96   2017-01-03 09:55:30 +08:00

*反应就是目录权限 +1
xiyangyang
    5

xiyangyang   2017-01-03 10:23:37 +08:00

用户是 nginx ,组是 devgroup 。
使用了如下命令:
255 sudo service php-fpm restart
256 sudo usermod -a -G devgroup nginx
257 sudo chown -R nginx /var/www
258 sudo chgrp -R devgroup /var/www
259 sudo chmod 2775 /var/www
260 find /var/www -type d -exec sudo chmod 2775 {} \;
261 find /var/www -type f -exec sudo chmod 0664 {} \;
262 sudo service nginx restart

这样的权限应该没问题吧?
结果还是一样。

falcon05
    6

falcon05   2017-01-03 10:30:55 +08:00 via iPhone

uploads 目录的权限改成 nginx 用户可写
xiyangyang
    7

xiyangyang   2017-01-03 10:38:44 +08:00

drwxrwsr-x 7 nginx devgroup 4096 Jan 2 17:33 uploads

还是不行。所以感觉很奇怪。

Showfom
    8

Showfom   2017-01-03 15:08:17 +08:00 via iPhone

你 nginx 是用什么用户运行的呢
xiyangyang
    9

xiyangyang   2017-01-03 15:13:53 +08:00

[root@ip-172-31-12-57 html]# ps -ef|grep nginx
root 27803 1 0 07:01 ? 00:00:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx 27805 27803 0 07:01 ? 00:00:00 nginx: worker process
root 27897 26845 0 07:13 pts/0 00:00:00 grep –color=auto nginx
xiyangyang
    10

xiyangyang   2017-01-03 15:25:49 +08:00

发现一个奇怪现象:
[root@ip-172-31-12-57 php-fpm.d]# ps aux | grep php
root 26463 0.0 0.7 398852 7836 ? Ss 03:02 0:00 php-fpm: master process (/etc/php-fpm.conf)
apache 26465 0.0 1.4 398948 14544 ? S 03:02 0:00 php-fpm: pool www
apache 26466 0.0 1.4 398948 14488 ? S 03:02 0:00 php-fpm: pool www
但是我的 www.conf 里面确实是用的 user 和 group 都是 nginx ,也重启过了。
不知奥为什么还是 apache

Apache httpd 是否完全有能力做到不重启/重载而应用新的配置文件

试了一下在站点根目录下的.htaccess 文件里加了一行
SSLCipherSuite kRSA+AESGCM

然后再用 Chrome 打开网站,密钥交换已经从 ECDHE_RSA 变成 RSA 了 全过程没有重启 /重载 httpd
说明修改.htaccess 来更改配置是有效的 能 Override 配置文件里对应项目且不用重启

所以说, Apache 是否完全有能力做到不重启 /重载而应用修改后的配置文件?

7 条回复    2017-03-01 23:40:22 +08:00

lhbc
    1

lhbc   2017-03-01 19:23:41 +08:00 via iPhone

可以,不过.htaccess 效率太低。
reload 更好,什么场景需要经常更改配置?
qiaoxin
    2

qiaoxin   2017-03-01 19:25:29 +08:00 via Android

apachectl -k graceful

service httpd reload
Hardrain
    3

Hardrain   2017-03-01 20:17:27 +08:00

@lhbc 我倒是似乎没有经常要修改配置的使用情景
不过为什么说.htaccess 效率低呢?
Hardrain
    4

Hardrain   2017-03-01 20:17:44 +08:00

@qiaoxin 这不还是 reload(重载)了么
lhbc
    5

lhbc   2017-03-01 20:39:42 +08:00

@Hardrain 因为每请求一个文件,都需要遍历所有上级目录的 .htaccess
比如有一个请求 GET /static/images/avatars/0.png, Apache 会扫一遍
/static/images/avatars/.htaccess
/static/images/.htaccess
/static/.htaccess
/.htaccess
然后把存在的 .htaccess 读取,解析配置,*后才能处理 0.png 的请求
你说效率低不低
Hardrain
    6

Hardrain   2017-03-01 23:11:41 +08:00

@lhbc 大致明白了
但是,子目录如果没有.htaccess 不就不会这样了么?
lhbc
    7

lhbc   2017-03-01 23:40:22 +08:00

@Hardrain 开了这功能就会扫,磁盘 IO 肯定是有的

ios::exceptions()函数

*近在学习OpenGL的时候,在shader保存到本地文件,读取shader文件的时候,碰到了如下形式的函数:

std::ifstream vShaderFile;

vShaderFile.exceptions(std::ifstream::failbit|std::ifstream::badbit);

try
{
//进行了一系列操作,但没有包含thrwo的函数;
}
catch(std::ifstream::failure e)
{
std::cout<<“ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ”<<std::endl;
}

由于本人C++功底也不好,以上代码有两点不太明白
1.vShaderFile.exceptions 这个函数是啥?
2.try语句中没有throw语句,catch语句应该去捕获什么异常?

在查阅了c++Reference之后,大致明白。 现在整理如下:
针对*个问题:什么是exceptions
这是一个ios流的成员函数:std::ios::exceptions。
他有两种重载的形式:

/*get(1)*/ iostate exceptions() const;
/*set(2)*/ void exceptions (iostate except);

根据注释可以很明显的看出,

The first form (1) returns the current exception mask for the stream.

The second form (2) sets a new exception mask for the stream and clears the stream’s error state flags (as if member clear() was called).

1是用来得到当前流的状态的,会返回诸如 goodbit,badbit,eofbit,failbit。
2是用来设置一个新的状态掩码,同时会清除流的状态标志。当流的状态变成所设置的状态的时候,就会抛出一个异常。这也是为什么在try中没有thrwo语句,而catch语句还能正常捕获的原因。
值得注意,流默认设置的状态掩码是 goodbit,所以当流出错的时候,不会主动抛出异常哦。

现在测试如下:
测试1

#include<iostream>
#include<string>

int main()
{
std::cin.exceptions(std::ios::failbit);//这里只设置了一个failbit的flag
try
{
int test;
while (std::cin >> test)
std::cout << test << std::endl;
}
catch (std::ios::failure e)
{
std::cerr << “Wrong” << std::endl;
std::cout << std::cin.exceptions() << std::endl;
std::cout << std::cin.rdstate() << std::endl;
}
return 0;
}

 

 

可以看到当输入不是int的a的时候,while的条件cin>>test抛出了一个错误,并被catch,
cin.exceptions返回的是2,
cin.rdstate返回的也是2,可以知道抛出以及捕获的过程中,并不会修正这个错误位。

测试2

#include<iostream>
#include<string>

int main()
{
std::cin.exceptions(std::ios::failbit|std::ios::eofbit);
try
{
int test;
while (std::cin >> test)
std::cout << test << std::endl;
}
catch (std::ios::failure e)
{
std::cerr << “Wrong” << std::endl;
std::cout << std::cin.exceptions() << std::endl;
std::cout << std::cin.rdstate() << std::endl;
}
return 0;
}

 

 

%title插图%num

这次测试数据和上次相同,但多设置了一个eofbit位置。
cin.exceptions返回的是3,和之前的2不同,说明cin.exceptions返回的是设置的异常掩码的状况;
cin.rdstate返回的和上次相同。

可见上述的“同时会清除流的状态标志”的意思是把之前设置的状态标识覆盖掉,改为现在设置的标志。

为IOStream平反

为IOStream平反​

很多Native的程序员钟情于printf / fprintf / …,
谈到C++的IOStream Library,大部分的意见都是:复杂、难用、不直接。其实,STL巨细靡遗、井然有序的特质,
在IOStream library里,体会的淋漓尽致,如果你想扩展OO的视野,那么IOStream*对是一颗沉睡的宝珠。 ​

一些基本概念​

  1. 流对象 Stream object​

C++里的IO是用“流”的概念来表示的。
所谓的“流”,就是一串字节序列。输出就是“流入”stream object,输入就是“流出”stream object。
而stream object,则可以理解为是一种具象的“流”的容器。 ​

  1. 流类 Stream class​

IO自身就种类繁多(输入、输出、文件操作),所以IOStream library也提供了不同的类来封装不同类型的IO。
其中*重要的两种:​

    • istream: 用于表示输入数据的stream class;​
    • ostream:用于表示输出数据的stream class;​

这两个类是basic_istream<>和basic_ostream<>的char类型实例化类。
实际上,IOStream library并不和某一个具体的字符类型相关。 ​

  1. 全局流对象 Global stream object​

IOStream library定义了一些istream和ostream的全局对象,对应操作系统的标准IO通道:​

    • cin:istream对象,对应C语言中的stdin,通常是操作系统中的键盘设备;​
    • cout:ostream对象,对应C语言中的stdout,通常是操作系统中的显示器;​
    • cerr:ostream对象,对应C语言中的stderr,通常这个流对象也连接到显示器设备,但是cerr是没有缓冲的;​
    • clog:ostream对象,C语言里没有对应的对象,clog输出是带有缓冲性质的,其余和cerr相同;​

通过这些对象,我们可以利用操作系统的重定向机制,把cout重定向到日志文件,而cerr / clog输出到屏幕。 ​

  1. 流操作符​

和一开始说的一样,C++用到流对象的方向来实现IO。stream operator<<表示流入流对象,表示输出;stream operator>>
表示流出对象,表示输入; ​

  1. Manipulators​

Manipulators是一种对象,这种对象用来改变输入流的解释方式或者输出流的格式化形式。
因此,manipulator并不一定产生实际输出或者会消费掉一个输入。其中*重要的几个manipulator:​

    • endl:输出\n,并且刷新输出缓冲区;​
    • ends:输入\0;​
    • flush:刷新输出缓冲区;​
    • ws:跳过空格读取;​

看到这里,你应该对IOStream library有一个轮廓性的认识了,下面我们的讨论,也都属于这5部分的范畴,跟我来。 ​

IOStream类的基础结构​

IOStream的层次结构如下图所示:

%title插图%num

在每一个方框内,上面的是模板类,下面是char和wchar_t的实例化类型。 ​

在ios_base中,定义了与字符类型和字符类型信息无关的属性,其中大部分都是状态和格式标记; ​

basic_ios<>从ios_base派生,定义了和字符类型信息相关的属性。
例如:特定字符类型使用的缓冲区。
这个缓冲区对象,是basic_streambuf<>类的派生类对象,并根据需要的字符类型进行实例化; ​

basic_istream<>和basic_ostream<>从basic_ios<>虚拟派生,并分别用来进行输入和输出。
和basic_ios<>一样,这两个类也不和具体的某一种字符类型相关,而是提供了两个模板参数,
一个用来定义字符类型,另一个用来定义和字符类型相关的信息。
我们常用的istream和ostream,就是char类型实例化的两个类; ​

basic_iostream<>从basic_istream<>和basic_ostream<>派生,该类型的流对象即可以进行输入操作,
也可以进行输出操作; ​

basic_streambuf<>是整个IOStream library的核心。
这个类定义了流对象可以使用的所有读写操作的接口。
所有的stream class都使用basic_streambuf<>提供的接口进行实际的IO操作; ​

更加详细的类定义​

和我们前面说得一样,IOStream library的类都带有两个参数,其中一个是字符的类型,另外一个是和字符类型相关的信息。
这个字符类型相关的信息包括:EOF的表示形式以及如何复制和移动字符序列等(也是基于类型萃取的方式实现的)。
通常情况下,字符的类型和这些附加的信息总是成对出现的,因此定义一个模板类来表达这些所有字符的公共属性,
并且,根据每一种字符类型进行特化是一个不错的主意。
STL提供了char_traits<charT> (charT表示字符的类型)来解决这个问题,并且为char和wchat_t提供了特化版本。 ​

namespace std {
template <class charT, class traits = char_traits<charT>>
class basic_ios;
typedef basic_ios<char> ios;
typedef basic_ios<wchar_t> wios
}

basic_ios使用的stream buffer类定义如下: ​

namespace std {
template < class charT, class traits = char_traits <charT > >
class basic_streambuf;
typedef basic_streambuf < char > streambuf;
typedef basic_streambuf <wchar_t > wstreambuf;
}

​看到这里,你应该可以想象到,basic_istream<>,basic_ostream<>和basic_iostream<>的实现也同样采取了
“类型参数化”的手段,并且,也有各自的char & wchar_t特化版本。 ​

namespace std {
template < class charT, class traits = char_traits <charT > >
class basic_istream;
template < class charT, class traits = char_traits <charT > >
class basic_ostream;
template < class charT, class traits = char_traits <charT > >
class basic_iostream;
typename basic_istream < char > istream;
typename basic_istream <wchar_t > wistream;
typename basic_ostream < char > ostream;
typename basic_ostream < char > ostream;
typename basic_iostream <wchar_t > iostream;
typename basic_iostream <wchar_t > wiostream;
}

有哪些全局对象​

前面我们说过,STL为char和wchar_t提供了一些预定义全局对象来访问标准的IO通道,4个针对char,4个针对wchar_t。​

类型​

名称​

目的​

istream​

cin​

从标准输入通道读取​

ostream​

cout​

向标准输出通道输出​

ostream​

cerr​

向标准错误通道输出错误信息​

ostream​

clog​

向标准日志通道输出日志信息​

wistream​

wcin​

从标准输入通道读取寬字符集输入​

wostream​

wcout​

向标准输出通道输出寬字符集​

wostream​

wcerr​

以寬字符集向标准错误通道输出错误信息​

wostream​

wlog​

以寬字符集向标准日志通道输出日志信息​

basic_ostream<>对所有的内建类型,以及char * / bool / void *进行了重载,重载的方式是,把第二参数按箭头的方向发送到对应的stream中。
默认条件下,这些标准的流对象都会和标准C流进行同步。(这是导致效率不高的罪魁祸首!)
当通过标准C++流对象写入缓冲区的时候,它会先刷新对应的C流,反之亦然,当然,这些同步会花费一些时间,如果你不希望这样,可以在任何输入输出之前,调用:

sync_with_stdio( false);

有哪些头文件​

上面提及的stream class分布在下面这些头文件里:​

  • <iosfwd>:所有stream class的前置声明;​
  • <streambuf>:stream buffer基类的定义;​
  • <istream>:basic_istream<>和basic_iostream<>的定义;​
  • <ostream>:basic_ostream<>的定义;​
  • <iostream>:全局流对象的声明;​

对于大部分的程序员来说,<iosfwd> / <istream> / <ostream>已经足够。
只有需要使用标准流对象的时候,才需要包含<iostream>,但由于初始化的问题,包含这个头文件会导致一小段代码的执行,进而对程序的执行效率稍有影响,虽然这小段代码自身的计算成本微不足道,但因此带来的一系列内存页面交换操作则可能进一步对性能产生影响。​

再说<<和>>操作符​

basic_istream<>和basic_ostream<>重载了<<和>>,并以此作为标准的IO操作符。 ​

<<

basic_ostream<>对所有的内建类型,
以及char * / bool / void *进行了重载,重载的方式是,把第二参数按箭头的方向发送到对应的stream中。
由于operator <<可以被重载,使得我们可以将任意的用户定义类型集成到IOStream library中。
其实,标准C++已经这样做了,string / bitset / complex对象均可以发送到std::cout,并且正常显示在屏幕上。 ​

和C里面,printf中的%d / %X / %O等等相比,这是一个长足的进步,
程序员不再需要指定待打印的字符的类型,编译器会进行正确的推导,并且正确显示。​

>>

和<<一样,basic_istream<>对所有的内建类型,以及char * / bool / void *进行了重载,重载的方式是,将读入参数发送到箭头所指参数。
同样,用户自定义类型也可以通过重载operator >>的方式集成到IOStream library,让我们像输入一个内建型别一样去输入一个用户自定义类型。 ​

特殊类型的IO​

  • bool:默认情况下,bool类型按照0 (false) / 1 (true)进行输出,输入时,0表示false,其他值表示true。
    但是值得注意的是:当输入非1表示true时,流状态会被设置std::ios_base::failbit标志。
    当然,通过国际化选项,C++也可以把bool输出成true / false或wahr / falsch(德语……)这样的文字;​
  • char和wchar_t:当读入这两个类型时,默认前置的空格将会被忽略;​
  • char *:通常,输入的起始空格会被忽略,通常,在输入字符串时,要指定一个*大安全长度:
    char buffer[81];
    std::cin>>std::setw(81)>>buffer;
    STL中的string类则更为智能,可以根据实际输入的字符串伸缩自如,所以,尽可能的使用std::string替代char * 吧。 ​
  • void *:当把一个void *类型的数据发送到basic_ostream<>时,将输出该指针指向的地址;​

到这里,我们关于IOStream library中和类型相关的讨论,就结束了,你应该对于整个库的层次结构熟记于心。
关于IO我们还有:流状态 / 标准IO函数 / 国际化这三个话题,希望我有时间,希望我能坚持写完~~~ ^.^​

IOStream library的stream对象维护了一组状态表达IO操作的结果(成功 or 失败?)以及失败的原因。
这次的内容我们就围绕着stream object展开。 ​

Stream object的状态​

流状态用ios_base::iostate这种类型的常量表示,C++标准里并没有强制iostate用枚举的方式来实现,int, std::bitset等也未尝不可。

iostate有下面四种状态: ​

iostate常量​

含义​

goodbit​

没有任何错误​

eofbit​

遇到文件末尾​

failbit​

一般性错误,IO操作没有成功​

badbit​

致命错误,会引发未定义的结果​

除了goodbit之外,其他的三个表示置1时表示真值,而goodbit则是全0,并不存在某一个bit表示good的概念。
eofbit通常和failbit是同时出现的,在IO操作超过文件结束位置的时候,先发生的是操作失败进而导致failbit被置位,而后,才是eofbit。 ​

操作iostate的成员函数​

这些成员函数定义在basic_ios<>里,用来处理流状态: ​

返回值​

函数​

说明​

bool​

good()​

如果流状态为goodbit,则返回true​

bool​

eof()​

如果eofbit被置位,则返回true​

bool​

fail()​

如果failbit或者badbit被置位,则返回true​

bool​

bad()​

如果badbit被置位,则返回true​

iostate​

rdstate()​

返回流对象当前的iostate​

void​

clear()​

清除流对象所有的iostate​

void​

clear(state)​

清除流对象所有的iostate,并把流状态设置成state指定的值​

void​

setstate(state)​

向流对象的状态中添加state指定的状态​

流状态和布尔条件​

为了在条件表达式里使用流对象,IOStream library重载了两个操作符void *和!。其中void *用来测试​

if (stream object)

!用于测试:​

if ( !(stream object))

值得说明的是,连续对state object使用两次!操作符并不会让state object恢复原来的状态,这是有悖于!操作符默认行为的举动,其实,明确调用state_obj.fail()进行判断是一个更好的办法。​

如果你执意要用!,那么,请在state_obj外围加上括号,因为!操作符的优先级,要比<<或>>高。对一个bool值进行IO是没有意义的。
例如 if (!cin>>a) 这是错误的.

流状态和异常​

和传统C语言通过返回值表示状态*大的不同,C++的异常是一种强制性的错误检测,
一旦程序中有代码抛出异常,你不处理,就会交由操作系统提供的默认异常处理程序接手,进而干掉发生异常的程序。
流对象在状态发生错误时,同样会抛出std::ios::failure异常只是出于兼容性考虑,这个抛异常的开关没有打开。 ​

STL提供了ios::exceptions()函数来打开这个开关,
不带参数调用的时候,返回当前打开异常开关的流状态,
另外一个重载版本带一个参数,打开参数指定的流状态异常。 ​

iostate exceptions( ) const;
void exceptions(
iostate _Newexcept
);
void exceptions(
io_state _Newexcept
);

几点说明:​

  • 0 或者 ios::goodbit 作为参数,不会导致异常; ​
  • 当调用过clear()或setstate()后,所有之前已经置位的错误流状态均会导致异常发生(具备检测作用.); ​
  • 对于异常本身,只有调用其what()函数这个做法是跨平台的,至于what()输出的内容,则没有保障其内容的一致性;​

至此,我们已经对IOStream library的结构、iostream对象和iostream状态有了清楚的认识。

实际上,除了重载过的<<和>>用于标准输入输出外,STL还提供了一组标准IO函数,他们定义在istream和ostream中。
和标准IO操作符不同的是,IO函数执行的是非格式化IO,而操作符执行的格式化IO(例如标准IO函数不会忽略前置空格)。 ​

标准IO函数​

STL中的标准IO函数都使用一个叫做streamsize的类型表达数量的概念,本质上说,这是一个带符号的size_t类型。 ​

标准输入函数​

在下面的故事里,istream只是一个替代符,用来代表basic_istream模板类以及basic_istream的任意一个实例化类。​

首先登场的是用户输入的函数:

函数​

终止条件​

读入字符​

自动添加结束符​

返回值​

get(void)​ EOF​ 1​ N/A​ 字符的int值或者其他​
get(char &c)​ N/A​ 1​ N/A​ istream &​
get(s, num)​ (‘\n’ or EOF)(excluding)​ up to num-1​ Yes​ istream &​
get(s, num, t)​ (t or EOF) (excluding)​ up to num-1​ Yes​ istream &​
getline(s, num)​ ‘\n’ or EOF (including)​ up to num-1​ Yes​ istream &​
getline(s, num, t)​ t or EOF (including)​ up to num-1​ Yes​ istream &​
read(s, num)​ EOF (exception)​ num​ no​ istream &​
readsome(s, num)​ EOF (no exception)​ up to num-1​ No​ streamsize​

这里,把一些区别性的东西额外摘出来,供大家记忆:​

按照是否在字符串后面自动添加结束标志分,可以分成两大类:​

  • 对s自动添加的:get / getline ​
  • 不自动添加的:read / readsome ​

get和getline的区别在于,get在delimeter之前会停止,并不读取delimeter;getline则会读取delimeter,但并不把读入的delimeter存到指定的字符串里。​

只有read是严格按照参数指定的个数进行读取的(所以有可能触发异常(未读满,即读到EOF)),其他函数的num参数只是读取的上限;

上面这些函数的都需要调用者保证,s有足够的空间存放读入的字符串,否则会发生未定义错误。​


接下来是和输入有关的一些辅助函数

函数​

说明​

返回值​

gcount()​ 返回*后一次非格式化读操作读取的字符数。​ streamsize​
ignore()​ 忽略输入流中的一个字符。​ istream &​
ignore(streamsize count)​ 忽略输入流中*多count个字符。​ istream &​
ignore(streamsize count, int delim)​ 忽略输入流中*多count个字符,直到遇到delim表示的字符,并且也会把delim忽略掉。​ istream &​
peek()​ 返回下一个要读取的字符,但是并不真正读取。​ int​
unget()​ 将*后一个读取的字符放回输入流。​ istream &​
putback(char c)​ 和unget()类似,但是putback会在读取操作发生之前检查,参数c是否是*后一个读入的字符。​ istream &​

同样,把一些细节的问题单独记在下面:​

对于ignore来说,如果参数count是numberic_limits<int>::max(),则在delim前所有的字符都会被忽略,或者遇到EOF。 ​

当putback()无法放回输入流或者要求放回的字符错误时,badbit被置位,并根据异常的设置抛出异常。
而对于*多能回写多少个字符,则是实现的细节问题,没有明确的标准。 ​

标准输出函数​

和标准输入函数类似,我们用ostream表示用于输出的流对象,它可以是ostream / wostream或者其他basic_ostream的实例化类对象。​

函数名​

说明​

返回值​

put(char c)​ 把字符c写入到输出流对象。​ ostream &​
write(const char *str,
streasize size)​
把str指向的字符串中的size个字符
写入到输出流对象。​
ostream &​
flush()​ 强制把输出流对象的缓存写入到输出流对象​ ostream &​

一些值得注意的地方:​

  • 可以通过检查返回的ostream对象的状态,来判定输出是否成功; ​
  • 对于write来说,字符串的结束符并不会导致输出停止,而是会被输出出来; ​
  • 调用者必须保证传递给write的str至少拥有size个字符,否则会发生未定义错误; ​

总结​

以上,就是我们常用的标准IO函数(没有格式化的),当我们需要操作C字符串的时候,用它们比用<<和>>更安全,
并经streamsize会经常出场提示你,关于容量方面的制约。

常用C++的你,一定熟悉std::cout<<std::endl的写法,你可曾想过,std::endl是如何工作的呢? ​

Manipulators的实现原理​

从*本质的方面来说,manipulator是通过函数重载实现的,各种运算符是被重载的函数。
而manipulator本身是一个函数,作为参数传递给被重载的函数,像下面这样: ​

ostream & ostream : : operator << (ostream &( *op)(ostream &)) {
return ( *op)( * this);
}

ostream &(*op)(ostream &)就是一个manipulator的原型,把需要manipulator处理的流对象按引用传入,并操作修改,然后返回,
例如我们*常见的std::endl: ​

std : :ostream & std : :endl(std : :ostream &strm) {
// Write a new line.
strm.put( ‘\n’);
// Flush the buffer.
strm.flush();
// Return the stream object.
return strm;
}

这样,当你写下std::cout<<std::endl的时候,就相当于调用了ostream的<<操作符,进而在<<运算符重载内部,变成了std::endl(std::cout),进而修改了ostream对象。 ​

把上面我们写过的实例化endl写成一般的版本,STL中的实现如下: ​

template < class charT, class traits >
std : :basic_ostream <charT, traits > &
std : : endl(std : :basic_ostream <charT, traits > &strm)
{
strm.put(strm.widen( ‘\n’));
strm.flush();
return strm;
}

这里,widen的作用是把\n转换成当前的流对象使用的字符集中对应的元素。 ​

常用的manipulator​

这里,我们列举一些istream和ostream中常用的manipulator:​

Manipulator​

Class​

含义​

flush 不是函数

basic_ostream​

刷新对应流对象的缓存。​

endl​

basic_ostream​

向流对象的缓冲区插入一个换行符,并刷新缓冲区。​

ends​

basic_ostream​

向流对象的缓冲区插入一个字符串结束符。​

ws​

basic_istream​

读入并忽略空格​

STL中还有一些带有参数的manipulators,为了使用它们,你需要包含iomanip头文件,它们的实现和endl这类不带参数的不同,与平台和实现版本相关,并没有一个统一的方式来定制。 ​

自定义manipulators​

可以按照std::endl()的方法,如法炮制一个你自己的manipulator出来。
例如,我们做一个istream的manipulator,用于忽略读入的当前行。 ​

template < class charT, class traits >
inline
std : :basic_istream <charT, traits > &
ignoreLine (std : :basic_istream <charT, traits > &strm)
{
strm.ignore(std : :numeric_limits < int > : :max(), trm.widen( ‘\n’));

return strm;
}

这样,你就可以像这样:std::cin>>ignoreLine;来使用它了(本质上来说这和调用std::cin.ignore(max(), c)是一样的)。​

两个方面的内容影响着I/O格式化的定义:
一方面,是一些诸如数字精度、填充字符或数制方面的标志;
另一方面,需要能够通过调整格式来满足不同地域习俗。
这次我们的话题围绕着格式化标志的内容展开;我们将在谈到国际化这个主题的时候来看如何处理另一方面的需求。 ​

格式化标志​

ios_base定义了一组表示I/O格式的成员标志,他们被用来指定诸如”*小宽度”、“浮点数精度”和“填充字符”等内容。
ios::fmtflags记录了所有可以被定义的I/O格式。 ​

STL还对常见的标志提供了分组,例如针对所有“八进制数”、“十进制数”和“十六进制数”生效的标志。
针对这些组,STL提供了特殊掩码来简化对“标志组”的访问。 ​

通过成员函数来修改format flags​

ios_base提供了一组用来设置和清除I/O format flags的函数: ​

成员函数​

含义​

返回值​

setf(flags)​

在原有标志上添加flags标志。​

修改之前的flags

setf(flags, mask)​

把mask指定的标志组的标志设定成flags。​

修改之前的flags

unsetf(flags)​

清除flags​

N/A​

flags()​

返回所有已经设置的flags。​

返回所有已经设置的flags

flags(flags)​

把格式标志设置成flag。​

返回修改前的flags

copyfmt(stream)​

复制stream流对象的格式标志。​

N/A​

为了便于理解,贴一段常用的保存->修改->恢复format flags的代码: ​

using std : :ios, std : :cout;
// save actual format flags
ios : :fmtflags oldFlags = cout.flags();
// do some changes
cout.setf(ios : :showpos | ios : :showbase | ios : :uppercase);
cout.setf(ios : :internal, ios : :adjustfield);
cout << std : :hex << x << std : :endl;
// restore saved format flag
cout.flags(oldFlags);
通过Manipulator修改format flags​

STL还提供了两个manipulators来操纵格式标志: ​

Manipulators​

含义​

setiosflags(flags)​

相当于调用setf(flags)。​

resetiosflags(mask)​

清除mask代表的标志组(相当于调用setf(0, mask)。​

一些用来定制I/O的函数和方法​

在STL中,有一些manipulator是通过模板特化实现的,通过特化,使得使用这些manipulator的代码更加易读和易用。
如果你在希望输出bool类型的时候不再是0 or 1;在输出浮点数的时候,能够统一精度;在输出数字的时候,能够统一宽度,那么下面的内容一定对你有用。 ​

bool变量的格式化输出​

ios::boolalpha标志定义了bool变量的输出方式,
置1 输出 true / false;
清0 输出 1 / 0。

我们可以通过std::boolalpha和std::noboolalpha这两个manipulator来置位和清除这个标志。​

bool b;
std : :cout <<std : :noboolalpha <<b << ” == ” <<std : :boolalpha <<b <<std : :endl;
关于宽度、填充字符​

ios_base类提供了两个函数来解决字段宽度和填充的问题:​

成员函数​

功能​

width()​

返回当前实际的域宽度。​

width(val)​

把当前宽度设置成val,并返回前一个宽度。​

fill()

返回当前的填充字符。

fill(c)​

把c定义成当前的填充字符,并返回上一个填充字符。​

width()对于输出流对象,定义了*小的输出宽度,但是它只对接下来的格式化输出有效。默认的*小宽度是0,表示任意宽度。 ​

谈到宽度和填充,自然就少不了如何对齐的问题,当实际宽度不足时,在左边、右边还是中间填充字符呢?ios_base定义了一组标志来处理对齐的问题: ​

标志掩码​

标志​

含义​

adjustfield​

left​

左对齐,也就是在右侧填充。​

adjustfield​

right​

右对齐,也就是在左侧填充。​

adjustfield​

internal​

这种对齐方式根据内容的不同,有不同的表达方式。​

我们可以使用函数setf(flag, mask)来设置这些表示。
这里需要注意的是,
任何格式化IO操作结束后,width会被自动重置成默认值,而填充字符和对齐方式在我们显式修改之前,不会改变。
所以说 width()[成员函数] 会被其他格式化IO自动重置,
setw()[格式操作符] 一般只对紧跟的一个输出有效.

下面是一些关于对齐的显示实例: ​

对齐方式​

width()​

-42​

0.12​

“Q”​

‘Q’​

left​

6​

-42___​

0.12__​

Q_____​

Q_____​

right​

6​

___-42​

__0.12​

_____Q​

Q_____​

internal​

6​

-___42​

__0.12​

_____Q​

_____Q​

STL中还定义了一些manipulators,来帮助我们定制格式化输出,它们是:​

Manipulator​

含义​

setw(val)​

把IO流对象的宽度设置成val,等同于width(val)。​

setfill(c)​

把IO流对象的默认填充字符设置成c,等同于fill(c)。​

left​

设置左对齐标志。​

right​

设置右对齐标志。​

internal​

设置internal对齐标志。​

于是,在没有manipulator之前,我们也许要这样写: ​

int a = – 42;
std : :cout.width( 6);
std : :cout.fill( ‘_’);
std : :cout.setf(ios : :left, std : :ios : :adjustfield);
std : :cout <<a <<std : :endl;

得益于manipulator,我们的代码简洁多了:​

std : :cout <<std : :setw( 6) <<std : :setfill( ‘_’) <<std : :left <<a <<std : :endl;
把width()用于控制输入域宽度​

width()可用户在输入标准C字符串的的时候限制读入的长度
当width!=0的时候,允许输入的*长字符数是width()–1。
例如:​

char buf[ 81];
std : :cin >>setw( sizeof(buf)) >>buf;

尽管如此,我们还是推荐在STL世界里,使用std::string来替代传统C字符串。​

负数标志和大写字母​

IOStream library中,两个表示和数值的显示有关系:

Flag​

Meaning​

showpos​

在正值前面加上’+‘。​

uppercase​

在输出浮点数或按十六进制输出的时候,字母的部分使用大写字母(默认使用小写)。​

除了使用setf来设置上述标志外,IOStream还提供了一些manipulator来处理这些标志。​

Manipulator​

Meaning​

std::showpos​

设置ios::showpos标志。​

std::noshowpos​

取消ios::showpos标志。​

std::uppercase​

强制使用大写字母。​

std::nouppercase​

强制使用小写字母。​

这些标志,在我们显式设置修改他们之前,它们一直会保持上一次被设置的状态。​

关于数制​

ios_base中定义了一组标志来定义整数值的IO使用的数值,这组标志用base::ios::basefield这个mask来选择。 ​

Mask​

Flag​

Meaning​

basefield​

oct​

8进制读写。​

basefield​

dec​

10进制读写。​

basefield​

hex​

16进制读写。​

basefield​

N/A​

按照10进制输出并根据输入的数值的前缀判断数制。​

对数制标志的修改会在标志被重置之前一直生效。当没有设置数制标志时,输入的数制根据输入的前缀来判定,例如,如果输入0x开头的数字则采用16进制,0开头的数字采用8进制,其他情况,是10进制。 ​

同样,除了使用setf设置上述标志外,IOStream也提供了对应的manipulator: ​

Manipulator​

Meaning​

oct​

设置8进制标志。​

dec​

设置十进制标志。​

hex​

设置16进制标志。​

一些常用的代码片段: ​

// Clear one flag and set another.
std : :cout.unsetf(std : :ios : :dec);
std : :cout.setf(std : :ios : :hex);

// Set one flag and clear all other flags in the group.
std : :cout.setf(std : :ios : :hex, std : :ios : :basefield);

// Use manipulators.
std : :cout <<std : :ios : :hex <<x <<std : :endl;

除了上面三个改变数制的标志外,IOStream还提供了一个控是否显式当前数制的标志:​

Flag​

Meaning​

std::ios::showbase​

当设置该标志后,八进制数显示时会加上前缀0,十六进制数显示时会加上前缀0x。 ​

同样,IOStream也提供了设置showbase的manipulator。 ​

Manipulator​

Meaning​

std::showbase​

设置showbase标志​

std::noshowbase​

取消showbase标志​

浮点数显示​

浮点数的格式化输出相对复杂一些,显示方式和精度共同控制着实际的显示效果。
显示方式有三种:fix / scientific / None。 ​

Mask​

Field​

Meaning​

floatfield​

fixed​

采用10进制显示​

floatfield​

scientific​

采用科学计数法显示​

floatfield​

N/A​

由IOStream决定*合适的方式​

显示的精度由precision()决定,该函数有两个重载版本:​

成员函数​

功能​

precision()​

返回当前 流状态的浮点数精度。​

precision(val)​

把精度设置成val并返回之前的精度。​

所有因为精度问题造成的“截断”都不会采用直接截断的方法,而是会在*后一位采用四舍五入。默认的精度是小数点后6位。
当precision()用于科学计数法的时候,用于指定小数点后的位数。
默认情况下,fix和scientific标志均未设置,IOStream判定的准则如下:小数点前有1个0,然后是所有必要的0。如果“precision()个”十进制数足够表现浮点数,则使用十进制表示,否则,使用科学计数法表示。 ​

IOStream还提供了一个标志用来控制小数点的显示,一般情况下,对于整数的显示,如果在精度范围内,不会显示小数点。开启showpoint后,将会强制显示小数点。​

无论是对精度、显示方式还是小数点的控制,都通过IOStream提供的一组manipulator来控制。​

Manipulator​

Meaning​

showpoint​

设置ios::showpoint标志​

noshowpoint​

取消ios::showpoint标志​

setprecision(val)​

设置精度为val​

fixed​

使用十进制格式显示​

scientific​

使用科学计数法显示​

浮点数的显示方式有些复杂,当你不知道如何是好的时候,可以参考下下面的表格: ​

显示方式​

precision()​

421.0​

0.0123456789​

Normal​

2​

4.2e+02

0.012​

Normal​

6​

421​

0.0123457​

Normal with showpoint​

2​

4.2e+02​

0.012​

Normal with showpoint​

6​

421.000​

0.0123457​

fixed​

2​

421.00​

0.01​

fixed​

6​

421.000000​

0.012346​

scientific​

2​

4.21e+02​

1.23e-02​

scientific​

6​

4.210000+e02​

1.234568e-02​

​还是试着说一下这个方式吧.

常规状态下: 精度表示从高往低,从*个不为0的数算起的位数(有效位数)
自动使用fixed或scientific中的一种. 根据精度是否能够恰当表达这个数值.选定一种方式,
若fixed方式表达不了,(值位数大于精度等),则采用scientific方式

非常规状态下: 精度表示为限定小数点后的位数
fixed 和scientific状态下, 都会显示小数点,除了某些指定精度为1的情况

通用格式化标志​

下面这两个标志不和具体某一个类型相关,单独放在这里:​

Flags​

Meaning​

skipws​

使用>>读取数值时,忽略起始空格。这个标志是缺省默认的。​

unitbuf​

每次输出操作后,清空输出缓冲区。cout默认不设置此标志,但是cerr和wcerr则作为默认设置。​

国际化相关的内容​

你可以让你的IO格式适应不同国家当地的习俗,ios_base提供了相关的函数来完成这个任务。 ​

成员函数​

作用​

imbue(loc)​

设置locale对象为loc​

getloc()​

返回当前的locale对象​

每一个流都可以关联一个属于自己的locale对象。
初始的locale对象是在流构建之初被指定的,其中locale定义了一些关于格式细节的内容,例如:数字的格式、小数点使用的字符或者boolean变量的文字表达形式。 ​

和C语言提供的本地化设置相比,你可以把每一个流配置自己的locale对象,这样,你可以按照美国数字格式读入,而按照德国格式输出。
对于不同locale,我想我们还需要专门一个话题,这里就不展开了。 ​

*后,IOStream提供了两个函数,用来把字符转换成和流的locale对应的字符集。 ​

成员函数​

含义​

widen(c)​

把字符c转换成和流locale字符集对应的字符。​

narrow(c, def)​

把字符c转换成一个char,如果没有对应的字符,则返回def。​

写在*后​

终于写完了,是的,我是说终于。
对于格式化,这个复杂的话题,陆陆续续整理和编写了半个月,如果你也看到了这里,我同样也要说,辛苦了。​

IOStream的用法总结

被复杂的IOStream弄晕了,因为经常会出现层层包裹的情况,学习了一天,发现其实挺有规律的,总结一下:

%title插图%num

%title插图%num

%title插图%num

%title插图%num

以输入流为例,输入流分为字节流和字符流,分别对应InputStream和Reader,而InputStreamReader是将InputStream封装成Reader的桥梁,一般会用于包装*外层的是BufferedReader,中间可能有FileReader或者InputStreamReader,其下再封装一层InputStream。有些流具有特殊的性质,比如带缓存、从文件读写、可以计数等,如果想要使用的流具有这个性质,则用其封装一次原流即可。

23

C++中头文件iostream介绍

C++语言不直接处理输入输出,而是通过一簇定义在标准库中的类型来处理IO。这些类型支持从设备读取数据、向设备写入数据的IO操作,设备可以是文件、控制台窗口等。还有一些类型允许内存IO,即,从string读取数据,向string写入数据。

C++/C++11中头文件<iostream>定义了标准输入/输出流对象。包含了<iostream>也自动包含了<ios>、<streambuf>、<istream>、<ostream>和<iosfwd>。

头文件<iostream>中的对象包括:

(1)、narrow characters(char)即窄字符:cin(standard input stream (object))、cout(standard output stream (object))、cerr(standard output stream for errors (object))、clog(standard output stream for logging (object));

(2)、wide characters(wchar_t)即宽字符:wcin(standard input stream (wide) (object))、wcout(standard output stream (wide) (object))、wcerr(standard output stream for errors (wide) (object))、wclog(standard output stream for logging (wide) (object))。

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 istream cin, *_Ptr_cin;
__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 ostream cout, *_Ptr_cout;
__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 ostream cerr, *_Ptr_cerr;
__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 ostream clog, *_Ptr_clog;

__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 wistream wcin, *_Ptr_wcin;
__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 wostream wcout, *_Ptr_wcout;
__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 wostream wcerr, *_Ptr_wcerr;
__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 wostream wclog, *_Ptr_wclog;

C++ IO heads, templates and class ( https://www.ntu.edu.sg/home/ehchua/programming/cpp/cp10_IO.html ):

%title插图%num

IO库:

(1)、istream(输入流)类型,提供输入操作;

(2)、ostream(输出流)类型,提供输出操作;

(3)、cin,一个istream对象,标准输入流,用来从标准输入读取数据;

(4)、cout,一个ostream对象,标准输出流,从标准输出写入数据,输出可以重定向( “>” 或“1>”)到一个指定文件中;用于将数据写入标准输出,通常用于程序的正常输出内容。

(5)、cerr,一个ostream对象,标准错误流,通常用于输出程序错误信息或与其它不属于正常逻辑的输出内容,写入到标准错误,默认情况下,写到cerr的数据是不缓冲的;错误信息可以直接发送到显示器,而无需等到缓冲区或者新的换行符时,才被显示;可以通过” 2> ”方式重定向输出到指定文件中;cerr通常用于输出错误信息或其它不属于程序正常逻辑的输出内容。

(6)、clog:一个ostream对象,标准错误流,关联到标准错误;与cerr区别:cerr和clog都是标准错误流,区别在于cerr不经过缓冲区,直接向显示器输出信息,而clog中的信息默认会存放在缓冲区,缓冲区满或者遇到endl时才输出;默认情况下,写到clog的数据是被缓冲的。clog通常用于报告程序的执行信息,存入一个日志文件中。

(7)、>>运算符,用来从一个istream对象读取输入数据;

(8)、<<运算符,用来向一个ostream对象写入输出数据;

(9)、getline函数,从一个给定的istream读取一行数据,存入一个给定的string对象中。

IO库类型和头文件:iostream定义了用于读写流的基本类型,fstream定义了读写命名文件的类型,sstream定义了读写内存string对象的类型,如下图:

%title插图%num

为了支持使用宽字符的语言,标准库定义了一组类型和对象来操纵wchar_t类型的数据。宽字符版本的类型和函数的名字以一个w开始。例如,wcin、wcout和wcerr是分别对应cin、cout和cerr的宽字符版对象。宽字符版本的类型和对象与其对应的普通char版本的类型定义在同一个头文件中。

测试代码如下:

#include “iostream.hpp”
#include <iostream>

// reference: http://www.tutorialspoint.com/cplusplus/cpp_basic_input_output.htm
int test_iostream_cout()
{
char str[] = “Hello C++”;
std::cout << “Value of str is : ” << str << std::endl;

return 0;
}

int test_iostream_cin()
{
char name[50];

std::cout << “Please enter your name: “;
std::cin >> name;
std::cout << “Your name is: ” << name << std::endl;

return 0;
}

int test_iostream_clog()
{
char str[] = “Unable to read….”;
std::clog << “Error message : ” << str << std::endl;

return 0;
}

int test_iostream_cerr()
{
char str[] = “Unable to read….”;
std::cerr << “Error message : ” << str << std::endl;

return 0;
}

// reference: https://msdn.microsoft.com/en-us/library/6xwbdak2(v=vs.80).aspx
static void TestWide()
{
int i = 0;
std::wcout << L”Enter a number: “;
std::wcin >> i;
std::wcerr << L”test for wcerr” << std::endl;
std::wclog << L”test for wclog” << std::endl;
}

int test_iostream_w()
{
int i = 0;
std::cout << “Enter a number: “;
std::cin >> i;
std::cerr << “test for cerr” << std::endl;
std::clog << “test for clog” << std::endl;

TestWide();

return 0;
}
GitHub:https://github.com/fengbingchun/Messy_Test

C++里面的iostream是什么

刚接触c++,我感觉很有意思,记录C++走过的坑

C++编译系统提供了用于输入输出的iostream类库。iostream这个单词是由3个部分组成的,即i-o-stream,意为输入输出流。在iostream类库中包含许多用于输入输出的类。

%title插图%num

ios是抽象基类,由他派生出istream类和ostream类,两个类名中*个字母i和o分别代表输入(input)和输出(output)。isrream类支持输入操作,ostream类支持输出操作,iostream支持输入输出操作。iostream是从istreanm类和ostream类通过多重继承而派生的类。

C++对文件的输入输出需要用ifstream和ofstream类,两个类名中*个字母i和o分别代表输入输出,第二个字母f代表文件(file)。ifstream支持对文件的输入操作,ofstream支持对文件的输出操作。类ifstream继承了istream,类ofstream继承了ostream,类fstream继承了iostream。

#include的意思提供iostream库中的信息,在程序开头写上这个才可以直接调用iostream类库中的函数.

include这个文件后,才能使用cin和cout。
准确地说,iostream是一个C++标准库的头文件。标准库的标准的含义就是说每个C++编译器都要自带的,无论用什么C++编译器都会有的,而且用法和行为是一样的。头文件内包含的只是你所使用的标准库内的类和函数的声明,实际上标准库的代码是编译好的(或者是类模板,这种情况会直接写在头文件中),你include这个头文件只是告诉编译器我要使用这里声明的东西,然后编译器负责将实际的库函数和你的代码一起生成exe文件。
你可以自己查找一下这个文件,这个文件就叫iostream没有扩展名,然后里面会include其他的头文件,你可以一层一层找下去看看cin和cout是怎么回事。
一见到 IO 这两个字母,基本上就是input 和output的缩写了,含义比较广泛,泛指计算机的输入和输出,不一定指iostream