CPPIO流

IO流

一、C++流介绍

定义:一段有序的字节序列

作用:主要用程序读取和写入数据

1、基本概念

流(Stream):在C++中,IO操作是通过流来完成的。流被看作是从源(如文件、键盘、网络连接等)到目标(如内存、磁盘等)的数据传输通道。

这种通道可以是单向的(如输入流或输出流)或双向的(如支持读写的文件流)。通过流可以实现程序与文件、网络套接字等进行数据交互。

2、C++中的流类库

C++中I/O(输入/输出)标准类定义在iostreamfstreamstrstream3个头文件中,对应的是标准I/O流文件I/O流字符串I/O流

  1. 标准I/O流 :涉及到与程序的标准输入(cin,通常关联着键盘)和标准输出(cout,通常关联着屏幕)设备的交互。此外,还包括错误输出流(cerr)和日志输出流(clog)等。
  2. 文件I/O流 :用于读写外部文件。C++提供了如ifstream(用于读取文件)、ofstream(用于写入文件)和fstream(既能读也能写)等类来处理文件操作。
  3. 字符串I/O流 :允许程序将数据读取到或写入到字符串中,主要通过istringstream(读取字符串)、ostringstream(写入字符串)和stringstream(可读写字符串)类实现。

各头文件包含的常用类如下:

  • 进行标准I/O操作时使用iostream头文件,它包含ios、iostream、istream、ostream等类
  • 进行文件I/O操作时使用fstream头文件,它包含fstream、ifstream、ofstream和fstreambase等类
  • 进行串I/O操作时使用sstream头文件,它包含istringstream、ostringstream、stringstream等类

二、ifstream流

ifstream 是 C++ 标准库中的一个类,用于从文件中读取数据。它是 istream 类的派生类,因此继承了所有用于输入操作的功能。使用 ifstream 可以打开文件、读取数据,并在完成操作后关闭文件。

1、打开文件

首先包含头文件:

cpp 复制代码
#include <fstream>
using namespace std;
(1)构造函数

方式一,可以直接在创建 ifstream 对象时指定文件路径。

cpp 复制代码
ifstream inputFile("example.txt");
(2)open()函数

方式二,先创建对象,然后使用 open 函数指定文件路径。

cpp 复制代码
ifstream inputFile;
inputFile.open("example.txt");
(3)状态检查

fail() 成员函数用来检查流是否处于失败状态,这包括读取或写入错误、格式匹配错误等情况。如果之前的操作导致流进入失败状态(比如文件打开失败,或者读写操作遇到不可恢复的错误),则fail()将返回true。此检查广泛用于确定是否出现了任何类型的错误。

cpp 复制代码
int main()
{
    ifstream inputFile("data.txt");
    if (inputFile.fail()){
        cerr << "无法打开文件!" << endl;
        return 0;
    }
}

或则:

cpp 复制代码
if (!inputFile) 
{
    cerr << "无法打开文件!" << endl;
    return 0;
}
    
if(!inputFile.is_open())
{
    std::cout << "文件打开失败" << std::endl;
    return -1;
}

这种用法利用了流对象可以直接作为布尔条件表达式的特性。当流对象用作条件时,它会隐式转换为其内部的bool值,这个值由!stream.fail()决定。如果流是好的(没有失败),表达式值为true;如果流失败了,则为false。所以这条语句也是检查流是否失败,与直接调用fail()效果相同,但在语法上更加简洁。

2、读取数据
(1)字符读取

get(ch)函数用于读取一个字符。其中,ch 是一个字符变量,用来接收从文件中读取的字符。

cpp 复制代码
char ch;
inputFile.get(ch);
cout << ch << endl;

如果成功读取到字符,该字符会被存储到 ch 中。

循环读取文件中的字符:

cpp 复制代码
char ch;
while (inputFile.get(ch)) 
{
    cout << ch;
}
(2)读取一行

getline 函数来自 <string> 头文件,专门用于处理 std::string 类型。其原型为:

cpp 复制代码
std::istream& getline(std::istream& is, std::string& str, char delim = '\n');

读取的文本将存储到字符串中,delim:默认分隔符是换行符(\n)。

cpp 复制代码
int main()
{
    //==========读取一行===============
    ifstream stream("example.txt");
    std::string line;
    std::getline(stream, line);
    cout << "读取一行数据:" << line << endl;
    //=====读取全部=====
    //循环继续调用getline读取剩余的每一行,直到文件结束。
    while (std::getline(stream, line))
    {
        cout << "读取一行数据:" << line << endl;
    }
}
3、提取运算符 (>>)

用于输入操作,从流中提取数据。例如,cin >> variable会从标准输入设备读取数据并存储到变量中。

另外,提取运算符可以连续使用,用于从流中顺序读取多个数据项。例如,从标准输入读取两个数字:

cpp 复制代码
ifstream inputFile("example.txt");
int number;
double decimal;
inputFile >> number >> decimal;

空白跳过 :默认情况下,>> 会自动跳过前导空白字符(如空格、制表符、换行符)。

ifstream使用提取运算符,循环从流中读取数据:

cpp 复制代码
ifstream inputFile("example.txt");
string s;
while (inputFile >> s) { 
    cout << "s: " << s << endl; 
}
4、关闭流
  • 显式关闭
cpp 复制代码
inputFile.close();
  • 自动关闭 :当 ifstream 对象离开作用域时,流会自动关闭。

三、ofstream流

ofstream 类,是 std::ostream 的派生类,用于处理文件的输出操作,即写入数据到文件中。

ofstream 可以创建新文件或覆盖现有文件并向其写入数据。ofstream<fstream> 头文件中。

1、创建流对象

创建一个 ofstream 类型的对象,可以在构造函数中指定文件名,或者先声明后使用 open() 函数指定文件。

cpp 复制代码
std::ofstream outputFile("output.txt");
2、检查状态

使用 is_open() 成员函数检查文件是否成功打开。

cpp 复制代码
if (!outputFile.is_open()) {
    std::cerr << "无法打开文件!" << std::endl;
    return 0;
}
3、写入数据

使用插入运算符 << 向文件写入各种类型的数据,如字符串、数字等。

cpp 复制代码
int main()
{
    ofstream outputFile;
    outputFile.open("data.txt");
    if(outputFile.is_open())
    { 
        outputFile << "hello world!\n";
        outputFile << 100 << std::endl;
    }
    else
    {
        cout << "文件打开失败" << endl;
    }
    outputFile.close();
    return 0;
}
4、关闭流

操作完成后,可以通过调用 close() 方法手动关闭,也可以在对象生命周期结束时也会自动关闭。

cpp 复制代码
outputFile.close();
5、文件流模式

默认以覆盖模式打开文件,如果需要追加内容而不是覆盖,可以在打开文件时设置相应的模式。

打开方式在ios类中定义,有输入方式、输出方式和追加方式等。

方式 作用 ifstream ofstream fstream
ios::in 用输入方式打开,只能读不能写 ×
ios::out 用输出方式打开,只能写不能读 ×
ios::app 以追加的方式打开文件,打开后文件指针在文件尾部,可以改写 ×
ios::binary 以二进制方式打开文件

上述参数可以结合运算符|一起使用,例如:

cpp 复制代码
ios::in | ios::out 以读写方式打开文件,对文件可读可写
cpp 复制代码
ios::in | ios::binary 以二进制方式打开文件,可以进行读操作
cpp 复制代码
int main()
{
    //使用追加模式打开文件
    ofstream outputFile("data.txt", ios::app);
    if(outputFile.is_open())
    { 
        outputFile << "hello world!\n";
        outputFile << 100 << std::endl;
    }
    else
    {
        cout << "文件打开失败" << endl;
    }
    outputFile.close();
}
6、图片复制案例
cpp 复制代码
#include <fstream>
#include <iostream>

int main () {

	std::ifstream input("123.png",std::ios::binary);
	std::ofstream output("456.png", std::ios::binary);
	char buffer[1024];
	while (input.read(buffer,1024)) {
		output.write(buffer, input.gcount()); //input.gcount():输出流每次读取真实大小

	}
	if (input.gcount() > 0) {
		output.write(buffer, input.gcount());
	}
	//图片较小可以直接用下面代码
	//output << input.rdbuf();
	return 0;
}

或者

cpp 复制代码
#include <iostream>
#include <fstream>//包含输入输出流头文件
using namespace std;
int main03()
{
	//复制照片
	ifstream input("OIP-C.webp", ios::binary);//二进制方式打开
	if(!input.is_open())
	{
		cout << "文件打开失败" << endl;
		return -1;
	}
	else
	{
		cout << "文件打开成功" << endl;
	}
	//输出文件流
	ofstream output("copy.webp", ios::binary);//二进制方式打开
	if(!output.is_open())
	{
		cout << "文件打开失败" << endl;
		return -1;
	}
	else
	{
		cout << "文件打开成功" << endl;
	}
	//读取数据
	char ch;
	while(input.get(ch)) //读取一个字符
	{
		output.put(ch); //写一个字符
	}
	//关闭流
	input.close();
	return 0;
}