C++相关闲碎记录(17)

1、IO操作

(1)class及其层次体系
(2)全局性stream对象
(3)用来处理stream状态的成员函数

前四个成员函数可以设置stream状态并返回一个bool值,注意fail()返回是failbit或者badbit两者中是否任一个设置,如果调用不带参数的clear(),所有的error flag均会被清除。

下面这个例子用于检查failbit是否设置,若设置则清除。

cpp 复制代码
if(strm.rdstate() & std::ios::failbit){
    std::cout << "failbit was set" << std::endl;
    strm.clear(strm.rdstate() & ~std::ios::failbit);
}
(4)stream异常

下面的例子要求所stream对所有的flag均抛出异常:

cpp 复制代码
strm.exceptions(std::ios::eofbit | std::ios::failbit | std::ios::badbit);

但是如果传入0或者goodbit,就不会引发异常。

cpp 复制代码
strm.exceptions(std::ios::goodbit);

异常抛出的时机是在"程序调用clear()或setstate()之后"又设置了某些flag之际,如果某个标志已被设置但未被清除,也会抛出异常。

下面的例子从输入中读取浮点数,直到end-of-file为止,返回总和。

cpp 复制代码
#include <iostream>
#include <exception>
#include <cstdlib>

namespace MyLib {
    double readAndProcessSum (std::istream&);
}

int main()
{
    using namespace std;
    double sum;

    try {
        sum = MyLib::readAndProcessSum(cin);
    }
    catch (const ios::failure& error) {
        cerr << "I/O exception: " << error.what() << endl;
        return EXIT_FAILURE;
    }
    catch (const exception& error) {
        cerr << "standard exception: " << error.what() << endl;
        return EXIT_FAILURE;
    }
    catch (...) {
        cerr << "unknown exception" << endl;
        return EXIT_FAILURE;
    }

    // print sum
    cout << "sum: " << sum << endl;
}

#include <istream>

namespace MyLib {
    double readAndProcessSum (std::istream& strm)
    {
        using std::ios;
        double value, sum;
    
        // save current state of exception flags
        ios::iostate oldExceptions = strm.exceptions();
    
        // let failbit and badbit throw exceptions
        // - NOTE: failbit is also set at end-of-file
        strm.exceptions (ios::failbit | ios::badbit);
    
        try {
            // while stream is OK
            // - read value and add it to sum
            sum = 0;
            while (strm >> value) {
                sum += value;
            }
        }
        catch (...) {
            // if exception not caused by end-of-file
            // - restore old state of exception flags
            // - rethrow exception
            if (!strm.eof()) {
                strm.exceptions(oldExceptions);  // restore exception flags
                throw;                           // rethrow
            }
        }
    
        // restore old state of exception flags
        strm.exceptions (oldExceptions);
    
        // return sum
        return sum;
    }
}
(5)读写字符的成员函数
(6)输出控制manipulator
(7)用户自定义操控器
cpp 复制代码
#include <istream>
#include <limits>

template <typename charT, typename traits>
inline
std::basic_istream<charT,traits>&
ignoreLine (std::basic_istream<charT,traits>& strm)
{
    // skip until end-of-line
    strm.ignore(std::numeric_limits<std::streamsize>::max(),
                strm.widen('\n'));

    // return stream for concatenation
    return strm;
}

这个控制器用来忽略一行,如果要忽略多行,就调用多次

std::cin >> ignoreLine >> ignoreLine;

函数ignore(max, c)会略去input stream中的字符c之前的所有字符,如果前面的字符多余max个,就略去max个,如果先遇到stream结尾,就全部忽略。

cpp 复制代码
#include <iostream>
#include "ignore1.hpp"

int main()
{
    int i;
    std::cout << "read int and ignore rest of the line" << std::endl;
    std::cin >> i;

    // ignore the rest of the line
    std::cin >> ignoreLine;

    std::cout << "int: " << i << std::endl;

    std::cout << "read int and ignore two lines" << std::endl;
    std::cin >> i;

    // ignore two lines
    std::cin >> ignoreLine >> ignoreLine;

    std::cout << "int: " << i << std::endl;
}
cpp 复制代码
#include <istream>
#include <limits>

class ignoreLine
{
  private:
    int num;
  public:
    explicit ignoreLine (int n=1) : num(n) {
    }
    
    template <typename charT, typename traits>
    friend std::basic_istream<charT,traits>&
    operator>> (std::basic_istream<charT,traits>& strm,
                const ignoreLine& ign)
    {
        // skip until end-of-line num times
        for (int i=0; i<ign.num; ++i) {
            strm.ignore(std::numeric_limits<std::streamsize>::max(),
                        strm.widen('\n'));
        }

        // return stream for concatenation
        return strm;
    }
};
cpp 复制代码
#include <iostream>
#include "ignore2.hpp"

int main()
{
    int i;
    std::cout << "read int and ignore rest of the line" << std::endl;
    std::cin >> i;

    // ignore the rest of the line
    std::cin >> ignoreLine();

    std::cout << "int: " << i << std::endl;

    std::cout << "read int and ignore two lines" << std::endl;
    std::cin >> i;

    // ignore two lines
    std::cin >> ignoreLine(2);

    std::cout << "int: " << i << std::endl;

    std::cout << "read int: " << std::endl;
    std::cin >> i;
    std::cout << "int: " << i << std::endl;
}
(8)format flag格式标志
cpp 复制代码
//set flags showpos and uppercase
std::cout.setf(std::ios::showpos | std::ios::uppercase);
//set only the flag hex in the group basefield
std::cout.setf(std::ios::hex, std::ios::basefield);
//clear the flag uppercase
std::cout.unsetf(std::ios::uppercase);
cpp 复制代码
using std::ios;
using std::cout;
//save current 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;
cout.flags(oldFlags);
(9)文件读写
(10)文件flag
cpp 复制代码
//seek to the beginning of the file
file.seek(0, std::ios::beg);
//seek 20 characters forward
file.seek(20, std::ios::cur);
//seek 10 characters before the end
file.seek(-10, std::ios::end);
(11)重定向
cpp 复制代码
#include <iostream>
#include <fstream>
#include <memory>
using namespace std;

void redirect(ostream&);

int main()
{
    cout << "the first row" << endl; //输出控制台

    redirect(cout);  //重定向到文件中,执行完毕之后,又重新指向控制台

    cout << "the last row" << endl;//指向控制台
}

void redirect (ostream& strm)
{
    // save output buffer of the stream
    // - use unique pointer with deleter that ensures to restore
    //     the original output buffer at the end of the function
    // 定义了一个删除器
    auto del = [&](streambuf* p) {
                   strm.rdbuf(p);
               };
    // 使用智能指针的目的时在退出函数时,还原ostream
    unique_ptr<streambuf,decltype(del)> origBuffer(strm.rdbuf(),del);

    // redirect ouput into the file redirect.txt
    ofstream file("redirect.txt");
    // strm指向file缓冲区
    strm.rdbuf (file.rdbuf());
    // 此两字符都会写入到文件中
    file << "one row for the file" << endl;
    strm << "one row for the stream" << endl;
    // 程序结束时,调用智能指针的删除器,将输出重新指向p,而这个p就是strm.rdbuf()
} //
(12)可读写的stream

定义一个file stream缓冲区,并将它安装在两个stream对象上,

cpp 复制代码
std::filebuf buffer;
std::ostream out(&buffer);
std::istream in(&buffer);
buffer.open("example.txt", std::ios::in | std::ios::out);
cpp 复制代码
#include <iostream>
#include <fstream>
using namespace std;

int main()
{
    // open file "example.dat" for reading and writing
    filebuf buffer;
    ostream output(&buffer);
    istream input(&buffer);
    buffer.open ("example.dat", ios::in | ios::out | ios::trunc);

    for (int i=1; i<=4; i++) {
        // write one line
        output << i << ". line" << endl;

        // print all file contents
        input.seekg(0);          // seek to the beginning
        char c;
        while (input.get(c)) {
            cout.put(c);
        }
        cout << endl;
        input.clear();           // clear  eofbit and  failbit
    }
}
输出:
1. line
       
1. line
2. line
       
1. line
2. line
3. line

1. line
2. line
3. line
4. line
(13)stream 缓冲区接口

函数pubseekoff()和pubseekpos()控制读写动作的当前位置,究竟是控制读或者写,取决于最后实参,其类型为ios_base::openmode,如果没有特别指定,实参默认值为ios_base::in|ios_base::out,一旦设置ios_base::in,读的位置就会跟着改变,一旦设置ios_base::out,写的位置也会跟着变化,函数pubseekpos()会把stream当前位置移至第一实参指示的绝对位置上,函数pubseekoff()则把stream当前位置移至某个相对位置,偏移量由第一实参决定,起始位置由第二实参决定,可以是ios_base::cur, ios_base::beg, ios_base::end。两个函数都返回stream所在的位置或者一个无效的位置,将函数的结果拿来和对象pos_type(off_type(-1))比较(pos_type和off_type是处理stream位置时所用的类型),如果希望获取stream当前位置,可以使用pubseekoff(): sbuf.pubseekoff(0, std::ios:cur)。

(14)output stream 缓冲区的iterator

使用ostreambuf_iterator将一个字符串写入stream缓冲区内:

cpp 复制代码
std::ostreambuf_iterator<char> bufWriter(std::cout);
std::string hello("hello, world\n");
std::copy(hello.begin(), hello.end(), bufWriter);
(15)input stream 缓冲区的iterator

将输入缓冲区的字符输出:

cpp 复制代码
#include <iostream>
#include <iterator>
using namespace std;

int main()
{
    // input stream buffer iterator for cin
    istreambuf_iterator<char> inpos(cin);

    // end-of-stream iterator
    istreambuf_iterator<char> endpos;

    // output stream buffer iterator for cout
    ostreambuf_iterator<char> outpos(cout);

    // while input iterator is valid
    while (inpos != endpos) {
        *outpos = *inpos;    // assign its value to the output iterator
        ++inpos;
        ++outpos;
    }
}
相关推荐
不想当程序猿_几秒前
【蓝桥杯每日一题】分糖果——DFS
c++·算法·蓝桥杯·深度优先
cdut_suye12 分钟前
Linux工具使用指南:从apt管理、gcc编译到makefile构建与gdb调试
java·linux·运维·服务器·c++·人工智能·python
波音彬要多做36 分钟前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法
捕鲸叉37 分钟前
C++软件设计模式之外观(Facade)模式
c++·设计模式·外观模式
只做开心事2 小时前
C++之红黑树模拟实现
开发语言·c++
程序员老冯头3 小时前
第十五章 C++ 数组
开发语言·c++·算法
程序猿会指北4 小时前
【鸿蒙(HarmonyOS)性能优化指南】启动分析工具Launch Profiler
c++·性能优化·harmonyos·openharmony·arkui·启动优化·鸿蒙开发
无 证明8 小时前
new 分配空间;引用
数据结构·c++
别NULL12 小时前
机试题——疯长的草
数据结构·c++·算法
CYBEREXP200813 小时前
MacOS M3源代码编译Qt6.8.1
c++·qt·macos