IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++_Primer_学习笔记_第八章(IO库) -> 正文阅读

[C++知识库]C++_Primer_学习笔记_第八章(IO库)

第二部分(C++标准库)

1).了解C++标准库设施很重要。
2).除了使用标准库读写与控制台相关联的流之外,学习其他的库类型,帮助我们读写命名文件以及完成string对象的内存IO操作。
3).标准库的核心是很多容器类和一族泛型算法,这些设施可以帮助我们编写简洁高效的程序。
4).标准库会去关注那些簿记操作的细节,特别是内存管理,这样我们的程序就可以将全部的注意力投入到需要求解的问题上。
5).vector的更多相关内容,以及顺序容器;string支持的操作,可以将string看成是只包含字符元素的特殊容器(它其实不是容器,只是很像);string支持很多容器操作,但不是全部。
6).泛型算法,这类算法通常在顺序容器一定范围内的元素上或者其他类型的序列上进行操作。例如,标准库提供了copy算法,完成一个序列到另一个序列的元素的拷贝;find算法,实现给定元素的查找……
7).泛型算法的通用性体现在两个方面,

  1. 可以用于不同类型的序列。
  2. 对序列中元素的类型限制小,大多数类型都是允许的。

8).关联容器,关联容器的元素是通过关键字来访问的。关联容器支持很多的顺序容器的操作,也定义了自己的一些操作。
9).动态内存管理相关的语言特性,和库设施。智能指针的一个标准版本,它是新标准库中最重要的类之一。通过使用智能指针,可以大幅度地提高使用动态内存代码的鲁棒性。
10).最后会给出一个较大例子,使用第二部分介绍的所有标准库设施。

第八章(IO库)

1).C++语言不直接处理输入和输出,而是通过定义一族定义在标准库中的类型来处理IO。这些类支持从设备中读取数据,向设备中写入数据的IO操作。设备可以是文件或者控制台窗口等,还有一些类允许内存IO,即从string中读取数据,向string写入数据。
2).IO库定义了读写内置类型值操作,此外,一些类,如string,通常也会定义类似的IO操作来读写自己的操作。(内置类型由标准库类型处理IO)
3).如何编写自己的输入输出运算符?如何控制输出格式以及如何对文件进行随机访问。
4).IO库设施,

  1. istream类型,提供输入操作,cin是一个istream对象,从标准输入中读取数据,
  2. ostream对象,提供写入操作,cout是它的一个对象,向标准输出中写入对象;cerr也是一个ostream对象,通常用于程序的错误消息,写入到标准错误中。
  3. >>,用来从一个istream对象读取数据,
  4. <<,用来向一个ostream对象中写入数据,
  5. getline函数,从给定的istream对象中读取一行数据,存入到给定的string对象。

/1.IO类

1).目前为止,我们使用过的IO类型和对象都是操纵char数据的。默认情况下这些对象都是关联到用户的控制台窗口的。
2).IO操作处理string中的字符会很方便,此外应用程序还可能读写需要宽字符支持的语言
3).为了支持以上的操作,标准库除了定义istreamostream外还有一些其他的IO类型。(一个类类型就在一个头文件中),分别定义在三个独立的头文件中

  1. iostream定义了用于读写流的基本类型,
  2. fstream定义了向读写命名文件的类型,ifstream,ofstream,ftream
  3. sstream定义了向内存string读写的操作。istringstream,ostringstream,stringstream

4).为了支持宽字符语言,标准库还特别定义了一组类型和对象来操纵wchat_t类型的数据。

  1. 宽字符版本的类型和函数的名字以一个W开始。例如,wcin,wcout,wcerr分别是cin,cout,cerr的宽字符版对象。
  2. 宽字符版本的类型和对象和其对应的普通char版本的类型定义在同一个头文件中。

5).注:流分为两类,char字符集,wchar_t字符集。
6).IO类型间的关系,概念上,设备和字符大小都不会影响我们的IO操作。

  1. 我们可以用>读取数据>,而不管是控制台窗口或者磁盘文件或者string中读取数据。
  2. 同样的,我们也不用管读取的字符能存入一个char对象内,还是需要一个wchar_t对象来存储。

7).标准库是通过继承机制,来做到这一点的。利用模板我们可以使用具有继承关系的类,而不必了解继承机制如何工作。
8).继承机制,可以使得我们可以声明一个特定的类型继承另一个类。我们通常可以将一个派生类(继承类)对象当作其基类(所继承的类)对象来使用。例如,ifstreamistringstream都继承自istream,所以我们怎么使用cin,就可以怎么使用继承类的对象。getline>>等。同理cout,如何使用,ofstreamostringstream的对象就如何使用。(cin->char in;cout->char out);
9).以上说明,本节以下介绍的都可以无差别的应用于普通流,文件流,string流,以及charwchar_t版本。

//1.IO对象无拷贝或赋值

1).注意:

{
    ofstream out1,out2;
    out1 = out2;//不可以对流对象进行拷贝
    oftream print (ofstream);
    //以上定义一个函数,但是,我们没有办法对一个流形参
    //进行赋值,也没有办法对一个流返回值进行赋值。
    out2 = print (out2);//错误,因为我们没有办法
    //对流形参赋值,对流返回值进行返回,更不能对流对象
    //赋值
}

2).进行IO操作的函数通常以引用的方式传递或者返回流。并且注意到,读写一个IO对象会改变其状态,因此传递和返回的引用不能是const

//2.条件状态

1).IO操作与生俱来的一个问题就是,可能发生错误。

  • 可恢复的错误;
  • 发生在系统深处的错误,超出了应用程序可以修正的范围;

2).IO类定义了一些函数和标志,帮助我们访问和和操纵流的条件状态

IO库的条件状态(s表示流对象)简要介绍
str::iostatestr是一种IO类型,(istream,ostream……);iostate是一种机器相关的类型,提供了条件状态的所有功能
str::badbit流已经崩溃
str::failbit一个IO操作失败
str::eofbit流到达了文件的末尾
str::goodbit流没有出现错误,为零
s.eof()如果eofbit置位(为1),那么返回true
s.good()流有效,返回true
s.bad()
s.fail()如果failbit或者badbit置为,返回1
s.clear()将流的状态全部复位(0),流的状态为有效,返回void
s.clear(str::iostate)将对应的(failbit和badbit两个条件为置0)条件为复位,`iostate & ~cin.badbit & ~cin.failbit
s.setstate(str::state)置为指定的状态,其实与上面一个没有什么区别
s.rdstate()读取流当前的状态

3).一个简单的错误的例子就是,int i;cin >> i;//如果我们输入字符或者文件结束标志,cin就会进入错误状态
4).一个流一旦发生错误,其后序的IO操作都会失败,只有一个流处于无错状态时,我们才可以从它读取数据,向它写入数据
5).由于一个流可能处于错误状态,所以代码应该先检查流是否处于良好的状态再对它进行使用。一个简单的检查方法就是,将它作为条件,while (cin >> word)
6).但是将流作为条件,只能知道流是否有效,而不能告诉我们流到底发生了什么。对于不同的问题,解决的办法是不一样的。
7).IO类型中的与机器无关的iostate应该作为位的集合来使用,就是进行一系列的位的操作。
8).注意,

  • 四个iostate是constexpr值,用来配合位运算。
  • badbit表示的是系统级别的错误,例如不可恢复的读写错误,它一旦被置位,流就不可以在使用了
  • failbit表示的是可以修正的错误,例如上述的期望一个int类型的但输入的是一个字符串的错误.流可以继续使用
  • eofbit和failbit都会被置位,当到达文件结束时。
  • goobit的值为0,表示流是有效的。
  • badbit,failbit,eofbit中的任何一个被置位(为1),检测流都是条件都是失败的。就是说不知道具体的原因。

9).auto state = s.rdstate();//注意auto的使用。

//3.管理输出缓冲

1).每一个输出流都管理一个缓冲区,用来保存程序的读写的数据,如果执行os << "hello world!";,文本可能会立即地打印出来,也可能被操作系统保存在缓冲区中,随后在进行打印。
2).缓冲区机制的优点,有了缓冲区机制,操作系统可以将程序的多个输出操作组合成单一的系统级别写操作。由于设备的写操作可能很耗时间,允许系统将多个输出操作组合在一起进行单一的设备写操作可以带来很大的性能提升。
3).导致缓冲刷新**(数据真正地写到输出设备或文件)**的原因有很多,

  • 程序的正常结束,**作为main函数中return操作的一部分,缓冲刷新被执行。
  • 缓冲满时,需要刷新缓冲,而后的数据才能继续写入缓冲区中。
  • 可以用操纵符endl显式地指出进行缓冲去的刷新。
  • 在每一个输出操作之后,我们是可以用操纵符unitbuf设置刷新流的内部状态,来清空缓冲区。默认情况下,对于cerr时设置unitbuf的,因此,写到cerr的内容时都是立即刷新的。
  • 一个输出流可能被关联到另一个流。在这种情况下,当读写被关联的流时,关联到的流的缓冲区会被刷新,例如,默认情况下,cincerr都关联到cout,因此进行读cin或者写cerr都会导致cout的缓冲区被刷新。

4).endl操纵符进行刷新缓冲区并进行换行的工作。

  1. ends操纵符,向缓冲区插入一个空的字符,然后刷新缓冲区。
  2. flush操纵符,刷新缓冲区,但是没有输出额外的符号。
  3. uintbuf操纵符,想要每一次输出操作之后都刷新缓冲区,可以使用unitbuf,它告诉流在接下来的每一个写的操作之后都进行一次``flush操作。而nounitbuf`操纵符则重置流,使其恢复使用正常的系统管理的缓冲区刷新机制。
{
    cout << unitbuf;//以下所有的输出操作都立即进行刷新缓冲区操作;
    

    cout << nounitbuf;//回到正常的缓冲方式
}

5).如果程序是异常终止的,那么输出缓冲区是不会被刷新的。当一个程序崩溃时,它所输出的数据很可能停留在输出缓冲区中等待打印。所以,当调试一个已经崩溃的程序时,需要确认那些你认为已经输出的数据确实已经刷新了。否则,可能将大量的时间浪费在追踪代码为什么没有执行上(即,输出语句为什么一直没有执行呢?),而实际上,代码已经执行了,只是程序崩溃之后缓冲区没有被刷新,数据数据被挂起没有打印而已。
6).关联输入和输出流,当一个输入流被关联到输出流时,去输入流中读取数据的操作,都会先刷新你关联的输出流。因为标准库将coutcin关联在一起的。所以一旦cin进行写的操作,cout的缓冲区就会被刷新。(谁先谁后呢?)
7).答案是,先刷新再读取数据。所有的交互式系统通常应该关联输入和输出。这样的好处就是,所有的输出,包括用户的提示信息,都会再读操作之前就被打印出来。
8).tie()IO类的成员函数,用来关联流,注意目前是只有关联到ostream的流。

  • 第一个版本是不接受参数,返回指向输出流的指针。如果该对象 当前关联到一个输出流,则返回的就是指向这个输出流的指针,如果没有关联到流,返回空指针。
  • 第二个版本,接受一个指向ostream的指针。将自己关联到这个ostream。返回同上(注意是未关联之前的,否则课本有误)。

9).注意,

  1. 我们既可以将istream关联到一个ostream,也可以将一个ostream关联到一个ostream。
  2. 解开一个流的指针,我们可以传递一个空指针。ostream *old_tie = cin.tie(nullptr);//返回的是cin之前关联的ostream
  3. 每一个最多关联到一个流,但是同一个流可以有多个流同时关联

/2.文件输入输出

1).三个IO类型。

  1. ifstream,从一个给定的文件读取数据。
  2. ofstream,向一个给定的文件写入数据。
  3. fstream,可以读写给定的文件。

2).由于继承性质,直接当成cincout使用就可以。
3).fstrwam,ofstream,ifstream,特有的操作。

名称作用
fstream fstrm创建一个未绑定的文件流。fstream是头文件fstream中定义的一个类型
fstream fstrm(s)创建一个fstream,并且打开一个名字为s的文件。s可以是string类型或者是指向c风格的字符串。这下构造函数都是explicit。默认的文件模式依赖于fstream的类型
ftream fstrm(s,mode)同上,但是指定了模式打开文件
fstrm.open()打开名字为s的文件,并且将文件与fstrm绑定。s同上。返回void
fstrm.close()关闭与fstrm绑定的文件,返回void
fstrm.is_open()返回一个bool值,指出与fstrm关关联的文件是否成功打开并且尚未关闭

//1.使用文件流对象

1).两个模式,读或者写。
2).对象的创建。

{
    ifstream in(infile);//open自动被调用,构造一个对象,并且打开指定的文件(关联)
    ostream out;//只是创建一个对象。
}

3).在一个使用基类类型的地方,我们可以使用继承类型对象来代替。**意味着我们可以,用fstream或者sstream类型来调用接受的是iostream类型的函数。**例如,在之前的read()``print()函数中,我们函数的形参是iostream&但是我们可以给他们传递fstream,并且我们注意到,fstream已经和文件进行了绑定。
4).注意,

  • 由于open会失败,且失败时,failbit会置位所以我们可以用简单的if来判断是否成功的打开文件了。
  • 对于一个已经打开文件的流调用open会导致fialbit被置位。随后试图使用文件流的操作都会失败。
  • 为了将文件流(已经关联一个文件了)关联到另一个文件中,我们必须先关闭已经关联的文件,in.close();in.open(ifile+"2");//打开第二个输入文件
  • 如果open成功,那么open会设置流的状态,使得good()变为true
  • 一个fstream对象离开其作用域时,与之关联的文件会自动关闭。也就是说,当一个fstream对象被销毁时,close会自动被调用。(自动析构

练习8.4,

  • getline(fstream,string);
  • 迭代器*it;不修改的迭代器,const_iterator;
  • 文件名,要包括后缀。

练习8.7,

  • 输出到指定文件,它会自己创建文件。
  • 用法和cout没有什么区别。

练习8.8

  • 默认情况下是,每一次都进行覆盖。
  • 在后面加上参数,进行追加模式。ofstream::app;

//2.文件模式

1).每一个流都有一个关联的文件模式,来指出如何使用文件。

方式含义
in以读的方式打开
out以写的方式打开
app每一次操作前都定位到文件末尾,也就是说,不会将前面的内容进行覆盖
ate打开文件后立即定位到文件末尾
trunc截断文件
binary以二进制方式进行IO,这个需要特别指定。

2).指定模式的时机。

  • 调用open打开文件时,第二个参数是mode。
  • 用文件名字进行初始化时,也是第二个参数。

3).注意,

  • 只可以对ofstreamfstream设定out模式。
  • 只可以对ifstteamfstream设定in模式。
  • 只可以在out模式下才可以设定trunc
  • 只要trunc没有被设定,就可以设定app模式。在app模式下。即使没有显式地指出位out模式,文件也默认是out
  • 默认情况下,就是trunc,(即文件会被覆盖),就是说以out打开的文件会被截断。为了保留以out模式打开的文件的聂荣,必须同时指定app或者,同时指定in,即打开文件同时进行读写操作。
  • atebinary可以用于任何类型的文件流对象中,可以和其他任何文件模式一起使用。

4).每一个文件流类型都默认了一个文件模式。没有指定就是默认的形式。

  1. ifstream,就是in
  2. ofstream,就是out
  3. fstream,就是inout

5).以下情况,文件都会被截断。

{
    ofstream out1 ("data.out");
    ofstream out2 ("data.out",ofstream::out);
    ofstream out3 ("data,out",ofstream::out | ofstream::trunc);
}

6).以下情况,文件内容会被保留。

{
    ofstream out1 ("data.out",ofstream::app);
    ofstream out2 ("data.out",ofstream::out|ofstream::app);
    //我们可以猜测,ofstream设置了两个的默认实参
}

7).open()也是一样的用法。第二个参数指明模式,没有则默认是outtrunc(对于ofstream)。

/3.string流

1).sstream头文件中定义了三个类型来支持内存IO。string就一个IO流一样。(类比文件的绑定。)

  • istringstreamstring中读取数据。
  • ostringstreamstring写入数据。
  • stringstream既可以向string写也可以读数据。

2).除了继承而来的操作,sstream还定义了一些特殊操作。

名称作用
sstream strm;strm是一个未绑定的sstream对象,sstream是头文件sstrem定义的一个类型。
sstream strm(s);strm是一个stream对象,保存一个string s拷贝,此构造函数时explicit的,不支持隐式转换。
strm.str()返回的是strm所保存的拷贝
strm.str(s)string s拷贝到strm中,返回void。(也就是说相当于将它重新构造)

//1.使用istringstream

1).对于整行文本中的单个的单词进行处理。

{   
    //个人信息类
    struct  PeopleInfo{
        string name;
        vector<string> phone;
    };
    ifstream in ("data.in");
    if(!in)//判断文件是否成功打开
    {
        cerr……
    }
    vector<PeopleInfo>  people;
    string line,word;//存放行和每一个电话号码,以便进行循环。
    //每一次从文件中读取一行。
    while (getline(in,line))
    {
        PersonInfo person;//方便进行操作
        istringstream record (line);//绑定string流
        record >> person.name;
        //存放每一个电话号码
        while(record >> word)
        {
            person.phone.push_back(word);
        }
        //一个人的信息记录完毕。
        people.push_back(person);
    }
    in.close();//关闭文件。
}

2).注意。

  • 对于输入流,它会依次读取下去。
  • 对一行string进行绑定就是为了实现,一行中单个单词的提取工作。
  • cin一样的,record(string流,一样的到达文件末尾一样的是failbit置位)

//2.使用ostringsrtream

1).验证每一个电话号号码都有效,我们才输出这个人。通过内存IO,达到简化目的。

{
    for (const auto &entry : people)
    {
        ostringstream formatted,badNums;
        for (const auto &nums : entry.phone)
        {
            if (!valid (nums))
                badNums << " " << nums;
            else
            {
                formatted << " " << format(nums);

            }
        }
        if (badNums.str().empty)    //没有错误数
            os << entry.name << " "
               << formatted.str() << endl;
        else
            cerr << "input error:" << entry.name
                 << "invalid number(s) " << badNums.str() << endl;
         
    }
}

2).分析。

  • 通过一种暂存机制,来达到检验的目的。
  • 注意到,str()返回的是一个string的拷贝,可以调用empty(),
  • string流的写入操作实际上就是向string对象添加字符。不仅如此,配合str()还可以输出。
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-11 16:27:42  更:2021-07-11 16:28:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/4 17:46:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码