21天学通C++读书笔记(二十六:使用流进行输入和输出)

1. 流的概述

  • C++流是读写(输入和输出)逻辑的通用实现,让您能够用统一的模式读写数据
  • 不管是磁盘或键盘读取数据,还是将输入写入显示器或磁盘,这些模式都相同
  • 您只需使用合适的流类,类的实现将负责处理与设备和操作系统相关的细节
  • std:cout 是 ostream 类的一个对象,用于输出到控制台,std::cin 让您能够从流中读取数据
  • 如果要将 Hello World 写入文本文件,可将同样的语法用于文件流对象 fsHello
    fsHello << "Hello World!" << endl;
    

2. 重要的 C++ 流类和流对象

  • std命名空间中常用的C++流类
类/对象用途
cout标准输出流,通常被重定向到控制台
cin标准输入流,通常用于将数据读入变量
cerr用于显示错误信息的标准输出流
fstream用于操作文件的输入和输出流,继承了ofstream 和ifstream
ofstream用于操作文件的输出流类,即用于创建文件
ifstream用于操作文件的输入流类,即用于读取文件
stringstream用于操作字符串的输入和输出流类,继承了istringstream 和ostringstream,通常用于在字符串和其他类型之间进行转换
  • cout、cin 和 cerr 分别是流类 ostream、istream 和 ostream 的全局对象,由于是全局对象,它们在 main() 开始之前就已初始化
  • std命名空间中常用于流的控制符
类/对象用途
输出控制符
endl插入一个换行符
ends插入一个空字符
基数控制符
dec让流以十进制方式解释输入或显示输出
hex让流以十六进制方式解释输入或显示输出
oct让流以八进制方式解释输入或显示输出
浮点数表示控制符
fixed让流以定点表示法显示数据
scientific让流以科学表示法显示数据
<iomanip>控制符
setprecision设置小数精度
setw设置字段宽度
setfill设置填充字符
setbase设置基数,与使用dec、hex 或oct 等效
setiosflag通过类型为std::ios_base::fmtflags 的掩码输入参数设置标志
resetiosflag将std::ios_base::fmtflags 参数指定的标志重置为默认值

3. 使用std::cout 将指定格式的数据写入控制台

3.1 使用std::cout 修改数字的显示格式
  • 使用 cout 和 <iomanip> 控制符以十进制、十六进制和八进制格式显示整数
#include <iostream>
#include <iomanip>
using namespace std;

int main(){
    cout << "Enter an integer: ";
    int input = 0;
    cin >> input;
    
    cout << "Integer in octal: " << oct << input << endl;
    cout << "Integer in hexadecimal: " << hex << input << endl;
    
    cout << "Integer in hex using base notation: ";
    cout<<setiosflags(ios_base::hex|ios_base::showbase|ios_base::uppercase);
    cout << input << endl;
    
    cout << "Integer after resetting I/O flags: ";
    cout<<resetiosflags(ios_base::hex|ios_base::showbase|ios_base::uppercase);
    cout << input << endl;
    
    return 0;
}
  • 使用 cout 以定点表示法和科学表示法显示Pi 和圆面积
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    const double Pi = (double)22.0 / 7;
    cout << "Pi = " << Pi << endl;
    
    cout << endl << "Setting precision to 7: " << endl;
    cout << setprecision(7);
    cout << "Pi = " << Pi << endl;
    cout << fixed << "Fixed Pi = " << Pi << endl;
    cout << scientific << "Scientific Pi = " << Pi << endl;
    
    cout << endl << "Setting precision to 10: " << endl;
    cout << setprecision(10);
    cout << "Pi = " << Pi << endl;
    cout << fixed << "Fixed Pi = " << Pi << endl;
    cout << scientific << "Scientific Pi = " << Pi << endl;
    
    cout << endl << "Enter a radius: ";
    double radius = 0.0;
    cin >> radius;
    cout << "Area of circle: " << 2*Pi*radius*radius << endl;
    
    return 0;
}

3.2 使用std::cout 对齐文本和设置字段宽度

  • 可使用 setw() 控制符来设置字段宽度,插入到流中的内容将在指定宽度内右对齐
  • 在这种情况下,还可使用 setfill() 指定使用什么字符来填充空白区域
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    cout << "Hey - default!" << endl;
    
    cout << setw(35);
    cout << "Hey - right aligned!" << endl;
    
    cout << setw(35) << setfill('*');
    cout << "Hey - right aligned!" << endl;
    
    cout << "Hey - back to default!" << endl;
    
    return 0;
}

4. 使用std::cin 进行输入

4.1 使用std::cin 将输入读取到基本类型变量中
  • 使用 cin 将输入读取到 int 变量中,将使用科学表示法的浮点数读取到 double 变量中,将三个字符分别读取到 char 变量中
#include<iostream>
using namespace std;

int main() {
    cout << "Enter an integer: ";
    int inputNum = 0;
    cin >> inputNum;
    
    cout << "Enter the value of Pi: ";
    double Pi = 0.0;
    cin >> Pi;
    
    cout << "Enter three characters separated by space: " << endl;
    char char1 = '\0', char2 = '\0', char3 = '\0';
    cin >> char1 >> char2 >> char3; // 使用一行代码将输入读取到三个字符变量中
    
    cout << "The recorded variable values are: " << endl;
    cout << "inputNum: " << inputNum << endl;
    cout << "Pi: " << Pi << endl;
    cout << "The three characters: " << char1 << char2 << char3 << endl;
    
    return 0;
}
4.2 使用std::cin:get 将输入读取到char*缓冲区中
  • 插入到 char 缓冲区中时不超越其边界
#include<iostream>
#include<string>
using namespace std;

int main() {
    cout << "Enter a line: " << endl;
    char charBuf[10] = {0};
    cin.get(charBuf, 9);
    cout << "charBuf: " << charBuf << endl;
    
    return 0;
}

尽可能不要使用 char 数组;只要可能,就应使用 std::string 而不是 char*

4.3 使用std::cin 将输入读取到std::string 中
#include<iostream>
#include<string>
using namespace std;

int main() {
    cout << "Enter your name: ";
    string name;
    cin >> name;
    cout << "Hi " << name << endl;
    
    return 0;
}
Enter your name: Siddhartha Rao
Hi Siddhartha

输出表明,只显示了我的名字,而不是整个输入字符串,这可能让您感到惊讶。为什么会这样呢?显然是由于 cin 遇到空白后停止插入

  • 要读取整行输入(包括空白),需要使用 getline()
#include<iostream>
#include<string>
using namespace std;

int main() {
    cout << "Enter your name: ";
    string name;
    getline(cin, name);
    cout << "Hi " << name << endl;
    
    return 0;
}

5. 使用std::fstream 处理文件

  • C++ 提供了 std::fstream,旨在以独立于平台的方式访问文件。std::fstream 从 std::ofstream 那里继承了写入文件的功能,并从 std::ifstream 那里继承了读取文件的功能
5.1 使用 open() 和 close() 打开和关闭文件
  • 要使用 fstream、ofstream 或 ifstream 类,需要使用方法 open() 打开文件
fstream myFile;
// open()接受两个参数:第一个是要打开的文件的路径和名称(如果没有提供路径,将假定为应用程序的当前目录设置)
// 第二个是文件的打开模式:在上述代码中,指定了模式ios_base::trunc(即便指定的文件存在,也重新创建它)、
//                       ios_base::in(可读取文件)和ios_base::out(可写入文件)
myFile.open("HelloFile.txt", ios_base::in|ios_base::out|ios_base::trunc);
if (myFile.is_open()) {  // check if open() succeeded
    // do reading or writing here
    myFile.close();
}
  • 保存到文件时,必须使用 close() 关闭文件流
  • 无论是使用构造函数还是成员方法 open() 来打开文件流,都建议在使用文件流对象前,使用 open() 检查文件打开操作是否成功
  • 可在下述各种模式下打开文件流
ios_base::app // 附加到现有文件末尾,而不是覆盖它
ios_base::ate // 切换到文件末尾,但可在文件的任何地方写入数据
ios_base::trunc // 导致现有文件被覆盖,这是默认设置
ios_base::binary // 创建二进制文件(默认为文本文件)
ios_base::in // 以只读方式打开文件
ios_base::out // 以只写方式打开文件
5.2 使用 open() 创建文本文件并使用运算符 << 写入文本
  • 使用 ofstream 新建一个文本文件并向其中写入文本
#include<fstream>
#include<iostream>
using namespace std;

int main() {
    ofstream myFile;
    myFile.open("HelloFile.txt", ios_base::out);
    
    if (myFile.is_open()) {
        cout << "File open successful" << endl;
    
        myFile << "My first text file!" << endl;
        myFile << "Hello file!";
    
        cout << "Finished writing to file, will close now" << endl;
        myFile.close();
    }
    return 0;
}
File open successful
Finished writing to file, will close now

// 生成的 HelloFile.txt 文件的内容如下
My first text file!
Hello file!
5.3 使用 open() 和运算符 >> 读取文本文件
#include<fstream>
#include<iostream>
#include<string>
using namespace std;

int main() {
    ifstream myFile;
    myFile.open("HelloFile.txt", ios_base::in);
    
    if (myFile.is_open()) {
        cout << "File open successful. It contains: " << endl;
        string fileContents;
    
        while (myFile.good()) {
            getline (myFile, fileContents);
            cout << fileContents << endl;
        }
        cout << "Finished reading file, will close now" << endl;
        myFile.close();
    } else {
        cout << "open() failed: check if file is in right folder" << endl;
    }    
    return 0;
}
5.4 读写二进制文件
  • 将一个结构写入二进制文件并使用该文件的内容创建一个结构
#include <fstream>
#include <iomanip>
#include <cstring>
#include <iostream>
using namespace std;

struct Human {
    Human() {};
    Human(const char* inName, int inAge, const char* inDOB) : age(inAge) {
        strcpy(name, inName);
        strcpy(DOB, inDOB);
    }
    char name[30];
    int age;
    char DOB[20];
};

int main() {
    Human Input("Siddhartha Rao", 101, "May 1916");
    ofstream fsOut ("MyBinary.bin", ios_base::out | ios_base::binary);
    if (fsOut.is_open()) {
        cout << "Writing one object of Human to a binary file" << endl;
        // reinterpret_cast 让编译器将结构解释为char*
        fsOut.write(reinterpret_cast<const char*>(&Input), sizeof(Input));
        fsOut.close();
    }
    
    ifstream fsIn ("MyBinary.bin", ios_base::in | ios_base::binary);
    if(fsIn.is_open()) {
        Human somePerson;
        fsIn.read((char*)&somePerson, sizeof(somePerson));
    
        cout << "Reading information from binary file: " << endl;
        cout << "Name = " << somePerson.name << endl;
        cout << "Age = " << somePerson.age << endl;
        cout << "Date of Birth = " << somePerson.DOB << endl;
    }
    return 0;
}

6. 使用std::stringstream 对字符串进行转换

  • 假设您有一个字符串,它包含字符串值 45,如何将其转换为整型值 45 呢?如何将整型值 45 转换为字符串 45 呢?C++提供的 stringstream 类是最有用的工具之一
#include<fstream>
#include<sstream>
#include<iostream>
using namespace std;

int main() {
    cout << "Enter an integer: ";
    int input = 0;
    cin >> input;
    
    stringstream converterStream;
    converterStream << input;
    string inputAsStr;
    converterStream >> inputAsStr;
    
    cout << "Integer Input = " << input << endl;
    cout << "String gained from integer = " << inputAsStr << endl;
    
    stringstream anotherStream;
    anotherStream << inputAsStr;
    int Copy = 0;
    anotherStream >> Copy;
    
    cout << "Integer gained from string, Copy = " << Copy << endl;
    
    return 0;
}
  • 只想读取文件时,务必使用 ifstream
  • 只想写入文件时,务必使用 ofstream
  • 插入文件流或从文件流中提取之前,务必使用 is_open() 核实是否成功地打开了它。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值