C++证道之路第十七章输入输出和文件

一、C++输入和输出概述

C++ 提供了丰富的输入/输出(I/O)功能,这些功能主要通过 <iostream> 头文件中的类和对象来实现。

1.流和缓冲区

C++把程序输入和输出看作字节流。输入时,程序从输入流中抽取字节;输出时,程序将字节插入到输出的流中。

管理输入包含两步:

①将流与输入去向的程序关联起来。

②将流与文件关联起来。

通常、通过使用缓冲区可以更高效的处理输入和输出。缓冲区是用作中介的内存块,它是将信息从设备传输到程序或从程序需传输到设备的临时储存工具。通常,像磁盘驱动器这样的设备以512字节或更多的块为单位来传输信息,而程序通常每次只能处理一个字节的信息。缓冲区帮助匹配这两种不同的信息传递速率。

这种原理与水库在暴风雨中收集几兆加仑的流量的水,然后以比较文明的速度给你家里供水时一样的。输出时,程序首先填满缓冲区,然后把整块数据传输给硬盘,并清空缓冲区,以备下一批输出是好用。这被称为刷新缓冲区。

2、流、缓冲区和iostream文件

管理流和缓冲区的工作有点复杂,但iostream文件中包含一些专门设计用来实现管理流和缓冲区的类。

3、重定向

标准输入和输出流通常连接着键盘和屏幕。但很多操作系统(包括unix、Linux、和Windows)都支持重定向,这个工具使得能够改变标准输入和标准输出。

二、使用cout进行输出

1.重载的<<运算符

在C++中,与C一样,<<运算符的默认含义是按位左移运算符。表达式x<<3的意思,将x的二进制表示中所有的位向左移动3位。显然,这与输出的关系不大。但ostream类重新定义了<<运算符,方法是将其重载为输出。在这种情况下,<<叫做插入运算符,而不是左移运算符(左移运算符由于其外观(像向左流动的信息流)而获得这种新角色)。插入运算符被重载,使之能够识别C++中所有的基本类型:

unsigned char;

signed char;

char;

short;

unsigned short;

int;

unsigned int;

long;

unsigned long;

long long;

unsigned long long;

float;

double;

long double;

2.其他ostream方法

除了各种operator<<()函数外,ostream类还提供了put()方法和write()方法,前者用于显示字符,后者用于显示字符串。

3.刷新输出缓冲区

在C++中,输出到控制台(通常是std::cout)或文件时,数据可能不会立即显示在目标位置,而是先被存储在缓冲区中。当缓冲区满或者某些特定条件被满足时,缓冲区的内容才会被刷新(即发送到其目标)。为了控制这种行为,C++提供了一些方法来手动刷新输出缓冲区。

std::endl是一个操纵符,它不仅插入一个换行符(就像'\n'),而且立即刷新输出缓冲区。这是最常用的刷新输出缓冲区的方法。

std::cout << "Hello, World!" << std::endl;

std::flush是一个操纵符,用于立即刷新输出缓冲区,但不插入任何字符。

std::cout << "Hello, World!" << std::flush;
4.用cout进行格式化

在C++中,使用std::cout进行格式化输出是常见的操作,它允许你控制输出的格式、精度、对齐方式等。

控制计数系统:

dec:设置基数为10,即十进制。

hex:设置基数为16,即十六进制。

oct:设置基数为8,即八进制。

std::cout << std::dec << 12 << std::endl; // 十进制输出12  
std::cout << std::hex << 12 << std::endl; // 十六进制输出C  
std::cout << std::oct << 12 << std::endl; // 八进制输出14

设置字段宽度:
 

std::setw(int n):设置下一个输出项的宽度为n个字符。如果输出项的长度小于n,则会在左侧(或右侧,取决于对齐方式)填充空格。

std::cout << std::setw(5) << 12 << std::endl; // 输出"   12"(宽度为5,右对齐)

对齐方式:

std::left:左对齐输出

std::right:右对齐输出(默认)

std::internal:在符号和数字之间填充空格(通常用于浮点数)

std::cout << std::left << std::setw(5) << 12 << std::endl; // 左对齐输出"12   "  
std::cout << std::right << std::setw(5) << 12 << std::endl; // 右对齐输出"   12"

设置填充字符:

std::setfill(char c):设置用于填充的字符

std::cout << std::setfill('*') << std::setw(5) << 12 << std::endl; // 输出"*12**"

设置浮点数的显示精度:

std::setprecision(int n):设置浮点数的精度为n位有效数字

std::cout << std::setprecision(2) << 3.14159 << std::endl; // 输出"3.1"

显示0和末尾的小数点:
std::cout.setf(std::ios_base::showpoint):强制显示小数点,即使它后面没有数字

std::cout.setf(std::ios_base::fixed):使用固定的小数点表示法,而不是科学记数法

std::cout << std::setprecision(2) << std::fixed << 3.0 << std::endl; // 输出"3.00"

三、使用cin进行输入

cin解释输入的方式取决于输入的数据类型。istream类(在iostream头文件中定义)重载了抽取运算符>>,使之能够识别下面这些基本类型:

signed char&

unsigned char &

char &

short &

unsigned short &

int &

unsigned int &

long &

unsigned long &

long long &

unsigned long long &

float &

double &

long double &

1.cin>>如何检查输入

检查流的状态:

可以通过检查std::cin的状态来查看输入是否成功。通常,我们关心两个状态标志:eofbit(表示已经到达文件末尾)和failbit(表示输入失败,通常是因为输入的数据类型与期望的不符)。

int num;  
if (std::cin >> num) {  
    // 输入成功  
    std::cout << "Input was successful: " << num << std::endl;  
} else {  
    // 输入失败,可能是非整数输入  
    std::cout << "Input failed!" << std::endl;  
    // 清除错误状态,以便后续输入  
    std::cin.clear();  
    // 忽略错误输入,直到遇到有效的输入  
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  
}

使用std::getline()和字符串解析:

可以使用std::getline来读取一行,然后尝试将其解析为你想要的数据类型。

std::string input;  
std::getline(std::cin, input);  

std::istringstream iss(input);  
int num;  
if (iss >> num) {  
    // 输入成功  
    std::cout << "Input was successful: " << num << std::endl;  
} else {  
    // 输入失败,可能包含非整数字符  
    std::cout << "Input failed!" << std::endl;  
}

使用异常处理:

std::cin本身不会抛出异常,但你可以使用自定义函数或包装器来在输入失败时抛出异常。

使用第三方库:

有些第三方库提供了更强大和灵活的输入验证和解析功能,例如Boost.Spirit。

2.流状态

在C++中,与流状态相关的知识点主要涉及std::istream(例如std::cin)和std::ostream(例如std::cout)对象的状态标志。这些状态标志用于指示流的状态,如是否成功读取或写入数据,是否遇到文件结束,或者是否发生错误。

状态标志:

eofbit:End-Of-File bit。当到达输入流的末尾时设置。

failbit:Fail bit。当输入/输出操作失败时设置,例如尝试从流中读取一个非数字的字符到int变量时

badbit:Bad bit。当发生严重错误时设置,如内存不足或无效流操作

goodbit:Good bit。当没有设置上述任何错误标志时设置。它是流状态的正常状态

检查流状态:

使用clear()成员函数可以重置流的状态标志。例如,cin.clear()将清除cin对象的所有错误标志

忽略输入:

如果输入流中有错误的输入,你可能想要忽略它并继续读取。可以使用ignore()成员函数来跳过字符,直到遇到特定的字符(默认为换行符)或读取了指定数量的字符

异常处理:

默认情况下,C++标准库流不会抛出异常来报告错误。但是,你可以通过设置流的异常掩码来更改此行为。例如,使用exceptions()成员函数可以设置当发生特定错误时流应抛出异常

错误处理:

当检测到输入错误时,通常的做法是清除错误状态,忽略错误的输入,并提示用户重新输入

流缓冲区:

流通常与缓冲区关联,该缓冲区用于存储待写入或待读取的数据。了解缓冲区如何工作以及何时刷新它们对于理解和处理流错误很重要

同步流:

在某些情况下,你可能希望将多个流(如std::cinstd::cout)同步,以确保它们按照预期的顺序进行读取和写入。可以使用std::ios_base::sync_with_stdio函数来实现这一点

流操纵器:

操纵器是用于修改流状态的特殊函数或对象。例如,std::endl不仅插入一个换行符,还刷新输出流。其他操纵器(如std::decstd::hexstd::setwstd::setfill等)用于格式化输出

文件流:

与标准输入/输出流类似,文件流(如std::ifstreamstd::ofstream)也有状态标志,并且可以使用相同的方法来检查、修改和处理这些状态

3.其他istream类方法

略,没意思

4.其他istream方法

略,没意思

四、文件输入和输出

C++I/O类软件包处理文件输入和输出的方式与处理标准输入和输出的方式非常相似。要写入文件,需要创建一个ofstream对象,并使用ostream方法。

1.简单的文件I/O

要让程序写入文件,必须这样做:
创建一个ofstream对象来管理输出流;

将该对象与特定的文件关联起来;

以使用cout的方式使用该对象,唯一的区别是输出将进入文件,而不是屏幕。

警告:以默认模式打开文件进行输出将自动把文件的长度截短为零,这相当于删除已有的内容。

读取文件的要求与写入文件相似:
创建一个ifstream对象来管理输入流;

将该对象与特定的文件关联起来;

以使用cin的方式使用该对象。

2.流状态检查和is_open()

.isopen()检查文件是否打开。

3.打开多个文件

如果需要同时打开两个文件,则必须为每个文件创建一个流。

注意:有些C++实现要求在该程序末尾使用fin.clear(),有些则不要求,这取决于将文件与ifstream对象关联起来时,是否自动重置流状态。使用fin.clear()是无害的,即使在不必使用它的时候使用。

4.命令行处理技术
wc report1 report2 report3

其中,WC是程序名,report1,report2,report3是作为命令行参数传递给程序的文件名。

注意:有些C++实现要求在该程序末尾使用fin.clear(),有些则不要求,这取决于将文件与ifstream对象关联起来时,是否自动重置流状态。使用fin.clear()是无害的,即使在不必使用它的时候使用。

5.文件模式

文件模式描述的是文件将被如何使用:读写,追加等。将流与文件关联时(无论是使用文件名初始化文件流对象,还是还是使用open()方法,都可以提供指定文件模式的第二个参数)

6.随机存取

随机存取指的是直接移动(不是依此移动)到文件的任何位置。随机存取常被用于数据库文件,程序维护一个独立的索引文件,该文件指出数据在主数据文件中的位置。这样,程序便可以直接跳到这个位置,读取(还可能修改)其中数据。

五、内核格式化

不说了,无聊

  • 51
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值