美文网首页
输入/输出流

输入/输出流

作者: 薛落花随泪绽放 | 来源:发表于2022-10-03 10:19 被阅读0次

流类简介

在C++的标准类库中,将与数据输入/输出相关的类统称为“流类".


image.png

istream类提供了流的大部分输入操作,对系统预定义的所有输入流重载提取运算符“>>”。ostream类对系统预定义的所有输出流重载插入运算符“<<”。
表7-1 常用I/O流类列表

类名 说明 包含文件
抽象流基类 ios 流基类 ios
输入流类 istream 通用输入流基类和其他输入流基类。cin是该类的对象 istream
ifstream 文件输入流类。用于从文件读取数据 fstream
输出流类 ostream 通用输出流基类和其他输出流基类。cout是该类的对象 ostream
ofstream 文件输出流类。用于向文件写入数据 fstream
输入输出流类 iostream 通用输入/输出流基类和其他输入/输出流基类 istream
fstream 文件输入/输出流类。既能从文件中读取数据,也能向文件中写入数据 fstream

常见的头文件有以下三个。

  • iostream
    包含操作所有输入/输出流所需的基本信息。
  • iomanip
    包含格式化I/O的带参数操纵符,可用于指定数据输入/输出的格式。
  • fstream
    包含处理文件的有关信息。

标准流对象

标准流对象是为用户提供的常用外设与内存之间通信的通道,对数据进行解释和传输,提供必要的数据缓冲等。

C++在头文件iostream中为用户预定义了4个标准流对象,分别是cin(标准输入流)、cout(标准输出流)、cerr(非缓冲错误输出流)和clog(缓冲错误输出流)。

重定向,是改变默认的输入来源,或改变默认的输出目的地。
重定向函数freopen的原型

FILE *freopen(const char *path,const char *mode,FILE *sream);

freopen()功能是将stream按mode指定的模式重定向到路径path指向的文件。

程序7-1 将标准输出cout重定向到文件

#include <iostream>
using namespace std;

int main()
{
    int x,y;
    cin>>x>>y;
    freopen("test.txt","w",stdout); //将标准输出重定向到文件test.txt
    if(y==0)        //除数为0则输出错误信息
        cerr<<"error."<<endl;
    else
        cout<<x<<"/"<<y<<"="<<x/y<<endl;
    return 0; 
} 

10 0
error.

编写程序,将从键盘读取10个整数更改为读取文件中的前10个整数,计算平均值
程序7-2 标准输入重定向为文件

#include <iostream>
using namespace std;
int main()
{
    int x,count,sum = 0;
    freopen("input.dat","r",stdin); //将标准输入重定向到文件input.dat
    for(count = 0;count<10;count++)
    {
        cin>>x;
        sum+=x;
    }
    cout<<"前10个整数的平均值 = "<<1.0*sum/10<<endl;
    return 0;
}

假设input.dat内容如下:
5 8 10 15 20 25 30 40 50 60 70 80 90 100 110 120

运行结果如下
前10个整数的平均值 = 26.3

表7-2 ios中错误状态字

标识常量 含义
goodbit 0X00 流状态正常
eofbit 0X01 文件结束符
failbit 0X02 I/O操作失败,数据未丢失,可以恢复
badbit 0X04 非法操作,数据丢失,不可恢复

在ios类中还有几个与流状态相关的成员函数。

  • 返回流是否结束 int eof() const
    返回eofbit的值。
  • 返回流是否处于正常状态 int fail() const
    返回failbit状态
  • 判定流是否正常 int good() const;int operator void *();
  • 返回流是否处于失败状态 int bad() const; int operator void !();
  • 返回状态字 int rdstate() const;
    返回流的当前状态
  • 恢复状态字 void clear(int nStata = 0);

程序7-3 标准输入重定向为文件并判断文件状态

#include <iostream>
using namespace std;
int main()
{
    int x,count,sum = 0;
    freopen("input.dat","r",stdin); //将标准输入重定向到文件input.dat
    for(count=0;count<10;count++)
    {
        cin>>x;
        sum+=x;
        if(cin.eof()) break;
    }
    cout<<"前"<<count<<"10个整数的平均值 = "<<1.0*sum/(count+1)<<endl;
    return 0;
}
若input.dat内容不变:
5 8 10 15 20 25 30 40 50 60 70 80 90 100 110 120

则
前10个整数的平均值 = 26.3

若数据改变
10 20 30 40 50 60 70 80

前8个整数的平均值 = 45

程序7-4 将从键盘输入的数据进行累加

#include <iostream>
#include <string>
using namespace std;

int main()
{
    char ch;
    int sum = 0,count=0,x;
    cout<<"请输入整数(按Ctrl+Z退出)"<<endl;
    do
    {
        while(cin>>x)       //使用组合键<Ctrl+Z> 结束输入
        {
            sum += x;       //计算累加和
            count++; 
        } 
        cout<<"确实要退出输入请按 Q";
        cin.clear();        //状态字清0,恢复流状态
        cin>>ch; 
    }while(toupper(ch)!='Q');
    cout<<"sum="<<sum<<",count="<<count<<endl;
    return 0;
}

控制I/0格式

c++进行I/O格式控制的方式一般有使用流操作符设置标志字调用成员函数

流操作符

表7-3 C++中常见数据类型的默认I/O格式

I/O的数据类型 默认的输入格式 默认的输出格式
short、int、long(signed、unsigned) 与整型常数相同 一般整数形式,负数前面有负号
float、double、long double 与浮点数相同 浮点或指数格式,取决于哪个更短
char(signed、unsigned) 第一个非空白字符 单个字符(无引号)
char *(signed、unsigned) 从第一个空白字符(空格、\t、\n等)开始到下一个空白字符结束 字符序列(无引号)
void * 无前缀的十六进制数 无前缀的十六进制数
Bool 将true或1识别为true,将false或0识别为false 1或0

C++在iostream中提供了一些常用的无参数的流操作符。
表7-4 iostream中常用流操作符

流操作符 作用 输入/输出
endl 输出一个新行符,并清空流 O
ends 输出字符串结束,并清空流 O
flush 清空流缓冲区 O
dec * 以十进制形式输入或输出整数 I/O
hex 以十六进制形式输入或输出整数 I/O
oct 以八进制形式输入或输出整数 I/O
ws 提取空白字符 O

注:“流操作符”栏中的星号“*”不是操作符的一部分,表示是默认设置。

在头文件iomanip中定义了一些用于格式控制的流操纵符。
表7-5 常用的用于格式控制的流操纵符

流操纵符 作用
fixed 以普通小数形式输出浮点数
scientific 以科学计数法形式输出浮点数
left 左对齐,即在宽度不足时将填充字符添加到右边
right 右对齐,即在宽度不足时将填充字符添加到左边
setbase(int b) 设置输出整数时的进制,b为8、10或16
setw(int w) 指定输出宽度为w个字符,或输入字符串时读入w个字符。一次有效
setfill(int c) 在指定输出宽度的情况下,输出的宽度不足时用ASCII码为c的字符填充(默认情况是用空格填充)
setprecision(int n) 设置输出浮点数的精度为n。在使用非fixed且非scientific方式输出的情况下,n即为有效数字最多的位数。如果有效数字位数超过n,则小数部分四舍五入,或自动变为科学计数法输出并保留一共n位有效数字;在使用fixed方式和scientific方式输出的情况下,n是小数点后面应保留的位数
setiosflags(fmtfalgs f) 通用操纵符。将格式标志f所对应的格式标志位置为1
resetiosflags(fmtfalgs f) 通用操纵符。将格式标志f所对应的格式标志位置为0(清除)
boolapha 把true和false输出为字符串
noboolalpha * 把true和false分别输出为1和0
showbase 输出表示数值进制的前缀
noshowbase * 不输出表示数值进制的前缀
showpoint 总是输出小数点
noshowpoint * 只有当小数部分存在时才显示小数点
showpos 在非负数值中显示+
noshowpos * 在非负数值中不显示+
skipws * 输入时跳过空白字符
noskipws 输入时不跳过空白字符
uppercase 十六进制数中使用'A'~'E'。若输出前缀,则前缀输出“0x”,科学计数法中输出’E‘
no uppercase * 十六进制数中使用'a'~'e'。若输出前缀,则前缀输出“0x”,科学计数法中输出’e‘
internal 数值的符号(正负号)在指定宽度内左对齐,数值右对齐,中间由填充字符填充

程序7-5 使用流操纵符控制整数输出

#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
    int n = 65535,m = 20;
    //1)分别输出一个整数的十进制、十六进制和八进制表示
    cout<<"1) "<<n<<"="<<hex<<n<<"="<<oct<<n<<endl;
    //2) 使用setbase分别输出一个整数的十进制、十六进制和八进制表示
    cout<<"2)"<<setbase(10)<<m<<"="<<setbase(16)<<m<<"="<<setbase(8)<<m<<endl;
    //3)使用showbase和setbase分别输出一个整数的十进制、十六进制和八进制表示
    cout<<"3)"<<showbase;   //输出表示数值进制的前缀
    cout<<setbase(10)<<m<<"="<<setbase(16)<<m<<"="<<setbase(8)<<m<<endl;
    return 0; 
}

1) 65535=ffff=177777
2)20=14=24
3)20=0x14=024

程序7-6 使用流操纵符控制浮点数输出

#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
    double x = 1234567.89,y = 1.23456789;
    //1)无格式控制时
    cout<<"无格式控制时: \t\t 1)x=("<<x<<"),y=("<<y<<")\n";
    //2)保留5位有效数字
    cout<<"保留5位有效数字: \t     2)x=("<<x<<"),y=("<<y<<")\n";
    //3) 保留小数点后5位
    cout<<"保留小数点后5位: \t     3)x=("<<fixed<<setprecision(5)<<x<<"),y=("<<y<<")\n";
    //4)科学计数法,且保留小数点后5位
    cout<<"科学计数法,且保留小数点后5位 :    4)x=("<<scientific<<setprecision(5)<<x<<"),y=("<<y<<")\n";
    
    //5)非负数显示正号,输出宽度为12字符,宽度不足时用'*'填补 
    cout<<"5)"<<showpos<<fixed<<setw(12)<<setfill('*')<<y<<endl;
    //6)非负数不显示正号,输出宽度为12字符,宽度不足时右边用填充字符填补
    cout<<"6)"<<noshowpos<<setw(12)<<left<<y<<endl;
    //7)输出宽度为12字符,宽度不足时左边用填充字符填补
    cout<<"7)"<<setw(12)<<right<<y<<endl;
    //8)宽度不足时,负号和数值分列左右,中间用填充字符填充
    cout<<"8)"<<setw(12)<<internal<<-y<<endl;
    return 0; 
}

无格式控制时:                   1)x=(1.23457e+006),y=(1.23457)
保留5位有效数字:                        2)x=(1.23457e+006),y=(1.23457)
保留小数点后5位:                        3)x=(1234567.89000),y=(1.23457)
科学计数法,且保留小数点后5位 : 4)x=(1.23457e+006),y=(1.23457e+000)
5)****+1.23457
6)1.23457*****
7)*****1.23457
8)-****1.23457

程序7-7 通过setw()控制输入格式

#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
    string s1,s2;
    cin>>setw(5)>>s1>>setw(3)>>s2;
    cout<<"s1="<<s1<<",s2="<<s2<<endl;
    return 0;
}

1234567890
s1=12345,s2=678

标志字

为满足不同用户对数据输入/输出格式的要求,C++提供了通过setiosflags()设置标志字进行格式控制的方式。setiosflags()是带参数的操纵符,在头文件iostream中,用以设置指定的标志,函数的参数为流的格式标志位。

表7-6 常见格式标志常量及含义

标志常量名 含义 输入/输出
ios::skipws 0X0001 跳过输入中的空白 I
ios::left 0X0002 按输出域左对齐,用填充字符填充右边 O
ios::right * 0X0004 按输出域右对齐,用填充字符填充左边 O
ios::internal 0X0008 在符号位或基数指示符后填入字符 O
ios::dec * 0X0010 转换为十进制基数形式 I/O
ios::oct 0X0020 转换为八进制基数形式 I/O
ios::hex 0X0040 转换为十六进制基数形式 I/O
ios::showbase 0X0080 在输出中显示基数指示符 O
ios::showpoint 0X00100 在浮点数时必须带小数点和尾部的0 O
ios::uppercase 0X00200 以大写字母表示十六进制数,科学计数法使用大写字母E O
ios::showpos 0X00400 正数前加”+“号 O
ios::scientific 0X00800 科学计数法显示浮点数 O
ios::fixed 0X001000 定点形式表示浮点数 O
ios::unitbuf 0X002000 插入操作后立即刷新流 O

程序7-8 通过setiosflags()设置标志字进行格式控制

#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
    double x = 12.34;
    cout<<"1)"<<setiosflags(ios::scientific|ios::showpos)<<x<<endl;
    cout<<"2)"<<setiosflags(ios::fixed)<<x<<endl;
    cout<<"3)"<<setiosflags(ios::fixed)<<setiosflags(ios::scientific|ios::showpos)<<x<<endl;
    cout<<"4)"<<resetiosflags(ios::showpos)<<x<<endl;   //清除要输出正号的标志
    return 0; 
}

1)+1.234000e+001
2)+12.34
3)+12.34
4)12.34

调用cout的成员函数

ostream类提供了在cout中控制输出格式的成员函数,常见的有:

  • 设置和返回标志字 long flags(long 1Flags); long flags() const;
  • 设置标志位 long setf(long 1Flags);
  • 清除标志位 long unsetf(long 1Flags);
  • 设置和返回输出宽度 int width(int w); int width() const;
  • 设置填充字符 char fill(char cFill); char fill() const;
  • 设置数据显示精度 int precision(int np); int precision() const;

表7-7 ostream类的成员函数及与其作用相同的流操纵符

成员函数 作用相同的流操纵符
precision(int np) setprecision(np)
widh(int nw) setw(nw)
fill(char cFill) setfill(cFill)
setf(long IFlags) setiosflags(IFlags)
unsetf(long IFlags) resetiosflags(IFlags)

程序7-9 使用cout中的函数控制输出格式

#include <iostream>
using namespace std;
int main()
{
    double values[] = {1.23,20.3456,300.4567,4000.56789,50000.1234567};
    cout.fill('*');     //设置填充字符为星号*
    for(int i = 0;i<sizeof(values)/sizeof(double);i++)
    {
        cout<<"values["<<i<<"]=(";
        cout.width(10);     //设置输出宽度
        cout<<values[i]<<")"<<endl; 
    } 
    cout.fill(' ');     //设置填充字符为空格
    for(int i = 0;i<sizeof(values)/sizeof(double);i++)
    {
        cout<<"values["<<i<<"]=(";
        cout.width(10);     //设置输出宽度
        cout.precision(i+3);    //设置保留有效数字 
        cout<<values[i]<<")"<<endl; 
    } 
    return 0; 
}

values[0]=(******1.23)
values[1]=(***20.3456)
values[2]=(***300.457)
values[3]=(***4000.57)
values[4]=(***50000.1)
values[0]=(      1.23)
values[1]=(     20.35)
values[2]=(    300.46)
values[3]=(   4000.57)
values[4]=(  50000.12)

ostream类还有一些输出流的成员函数。

  • 字符插入 ostream &put(char c);
  • 数据块插入 ostream & write(const char *pch,int nCount);

程序7-10 使用cont()函数

#include <iostream>
using namespace std;
int main()
{
    char c = 'a',str[80] = "0123456789abcdefghijklmn";
    int x = 65;
    cout<<"cout.put('a'): ";cout.put('a');
    cout<<"\ncout.put(c+25): ";cout.put(c+25);
    cout<<"\ncout.put(x): ";cout.put(x);
    cout<<"\ncout.write(str,20): ";
    cout.write(str,20);
    return 0;
}

cout.put('a'): a
cout.put(c+25): z
cout.put(x): A
cout.write(str,20): 0123456789abcdefghij

调用cin的成员函数

get()函数

从输入流中读取一个字符(包括空白字符),返回值就是该字符的ASCII码。
程序7-11 采用EOF判断输入是否结束

#include <iostream>
using namespace std;
int main()
{
    int n = 0;
    char ch;
    while((ch = cin.get())!=EOF)
    {
        cout.put(ch);
        n++;
    }
    cout<<"输入字符共计: "<<n<<endl;
    return 0;
}
I love C++.
I love C++.
^Z
输入字符共计: 12

getline()函数

从输入流中的当前字符开始读取bufSize-1个字符到缓冲区buf,或读到'\n'为止。

程序7-12 getline()函数功能演示

#include <iostream>
using namespace std;
int main()
{
    char buf[10];
    int i = 0;
    while(cin.getline(buf,10))      //若输入流的一行超过9个字符,则会报错
        cout<<++i<<":"<<buf<<endl;
    cout<<"last: "<<buf<<endl;
    return 0; 
}

Hello
1:Hello
This is 2
2:This is 2
123456789
3:123456789
abcdefghijk
last: abcdefghi

eof()函数 bool eof();

用于判断输入流是否已经结束。

ignore()函数 istream & ignore(int n=1,int delim=EOF);

跳过输入流中的n个字符,或跳过delim及其之前的所有字符。

例如,现有若干电话号码。提取号码

Home: 12345678901
Tel:12345678019
Office:19876543210

程序7-13 从输入的字符串中提取电话号码

#include <iostream>
using namespace std;
int main()
{
    char str[30];
    while(!cin.eof())
    {
        cin.ignore(10,':'); //在cin流中跳过':'之前的全部字符
        if(!cin.eof())
        {
            cin>>str;
            cout<<str<<endl;
         } 
    }
    return 0;
}

Home:12345678901
12345678901
Tel:12345678019
12345678019
Office:19876543210
19876543210

peek()函数 int peek();

返回输入流中的当前字符,但是并不将该字符从输入流中取走——相当于只是”看了一眼“将要读入的下一个字符,因此叫”窥视“。

程序7-14 日期格式转换

#include <iostream>
#include <iomanip>
#include <string>
using namespace std;

string Months[13] = {"","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};//西文格式的月份

int main()
{
    char ch;
    int year,month,day;
    while((ch=cin.peek())!=EOF)
    {
        if(ch>='A'&&ch<'Z')
        {
            string sMonth;
            cin>>sMonth>>day>>year;     //接收:月、日、年
            //查找月份完成转换
            for(month=0;month<12&&sMonth!=Months[month];++month); 
        }
        else
        {
            cin>>year;
            cin.ignore()>>month;
            cin.ignore()>>day;
            //以上3条语句等价于:cin>>year>>ch>>month>>ch>>day; 
        }
        cin.ignore();   //跳过\n
        cout<<setfill('0')<<setw(2)<<month;
        cout<<"-"<<setw(2)<<day<<"-"<<setw(4)<<year<<endl; 
    }
    return 0;
} 

Dec 3 1990
12-03-1990
2001.2.2
02-02-2001
Nov 10 2018
11-10-2018
Feb 12 2019
02-12-2019
1.1.1
01-01-0001

相关文章

  • IO流

    # Java 流式输入 输出原理 # Java 流的分类 # 输入 输出 流 类 # 常见的节点流 和 处理流 #...

  • IO流——其他流

    输入输出流,打印流,数据流 标准的输入、输出流 System.in 标准的输入流,默认从键盘输入,类型是Input...

  • I/O:读和写 及文件

    File类 输入 输出流 File类 构造方法: 作用 输入 输出流 InputStreamFileInputSt...

  • 输入/输出流

    流类简介 在C++的标准类库中,将与数据输入/输出相关的类统称为“流类". istream类提供了流的大部分输入操...

  • IO流之 数据输入输出流【待补充※】

    数据输入输出流 1.什么是数据输入输出流 DataOutputStream(FuileOutputStream()...

  • 《程序、java、IO流》

    <8月17日更新> 《概念部分-输入输出流》 1根据流动方向的不同,流分为输入流和输出流 2对于输入和输出流,由于...

  • Java IO

    面向字符的输入输出流 面向字节的输入输出流 小测试 压缩

  • Java_IO_基础

    字节输入输出流InputStream/OutputStream、与字符输入输出流Reader/Write Inpu...

  • IO

    IO文件读写 输入流输出流字节流字节输入流 InputStream字节输出流 OutputStream字符流字符输...

  • 04_03_管理及I/O重定向 、04_04_grep及正则表达

    输入输出的数据流分为三种:1标准输入,2标准输出,3标准错误输出 1、 输入的数据流: <-- 标准输入(stdi...

网友评论

      本文标题:输入/输出流

      本文链接:https://www.haomeiwen.com/subject/oofrartx.html