IO流

C++兼容C,所以C中的输入输出函数依然可以在C++中使用,但是直接把C的那套输入输出搬到C++中肯定无法满足C++的需求。

使用cout进行输出

cout格式化

格式设置完成之后将以对应格式打印,直到格式状态设置为其他的选项为止

cout<<showbase;					//设置显示进制前缀
cout << dec << "dec:" << 15 << endl;
cout << oct << "oct:" << 15 << endl;
cout << hex <<"hex:"<< 15 << endl;

另外一种对象设置的方法,了解即可,没上边的方便

cout.setf(ios::showbase); 		//设置显示进制前缀
cout << "dec" << 15 << endl; 	//默认10进制
cout.unsetf(ios::dec);    		//取消10进制	一定要取消
cout.setf(ios::hex);   			//设置16进制
cout << "hex:" << 15 << endl;

调整字节宽度以及填充字符

头文件:

#include <iomanip>
const char* str = "sirius";
cout.width(10);		//设置宽度
cout << str << endl;
cout.width(10);		//设置宽度
cout.fill('*');		//设置填充字符
cout << str << endl;
cout.precision(2);	//设置精度
cout << 3.1415 << endl;
输出结果:
    sirius
****sirius
3.1

setf()相关

常量 含义
ios_base::boolalpha 输入输出bool值,可以为ture或false
ios_base::showbase 显示前缀0x01
ios_base::showpoint 显示末尾的小数点
ios_base::showpos 在正数前加+
参数 含义
ios_base::fixed (默认)使用定点计数法
ios_base::scientific 使用科学计数法
ios_base::left 使用左对齐
ios_base::right (默认)使用右对齐
ios_base::internal 符号或者基数前缀左对齐,值右对齐

字符串流

头文件

#include <sstream>
#include <iostream>
#include <sstream>
using namespace std;
int main() {
	//类型转换
	string res = "100";
	int num = 0;
	stringstream ss;
	ss << res;
	ss >> num;
	cout << num << endl;

	//分割字符串+类型转换
	string ip = "192.168.0.1";
	stringstream ss1(ip);
	int a1, a2, a3, a4;
	char ch;
	ss1 >> a1 >> ch >> a2 >> ch >> a3 >> ch >> a4;
	cout << a1 << " " << a2 << " " << a3 << " " << a4 << " " << ch << endl;

	//拼接字符串
	stringstream ss2;
	num = 3;
	char str[] = "14159";
	ss2 << num << ch << str;
	cout << ss2.str() << endl;
	return 0;
}
输出:
100
192 168 0 1 .
3.14159

文件流

头文件:

#include<fstream>

文件流常用函数

函数名 描述
open 打开文件
is_open 文件是否被打开
close 关闭文件
getline 读取一行
read 输入(读)到对象
write 输出(写)到文件
flush 将缓冲区的数据写出到文件,再清空它
tellg 输入(读)文件指针位置
tellp 输出(写)文件指针位置
seekg 设置输入(读)文件指针位置
seekp 设置输出(写)文件指针位置
eof 是否到了流尾部

**C++ **和 C的文件打开模式

**C++**模式 C模式 描述
ios_base::in “r” 打开以读取
ios_base::out “w” 等价于ios_base::out | ios_base::trunc
ios_base::out | ios_base::trunc “w” 打开以写入,如果已存在,则截断文件
ios_base::out | ios_base::app “a” 打开以写入,只追加
ios_base::out | ios_base::in “r+” 打开以读写,在文件允许的位置写入
ios_base::out | ios_base::in | ios_base::trunc “w+” 打开以读写,如果已存在,则截断文件
ios_base::binary “b” 以二进制的形式打开

截断文件:在文件写入之前擦除掉所有数据

open第三个参数

模式 描述
_SH_DENYRW 拒绝读写
_SH_DENYWR 拒绝写
_SH_DENYRD 拒绝读
_SH_DENYNO 可读写
_SH_SECURE 安全模式,向前兼容

示例程序:

#include<iostream>
#include<fstream>
using namespace std;
struct Student
{
	char name[20];
	int num;
	int age;
	char gender;
};
int main()
{
	fstream inFile;
	ofstream outFile;
	Student stu[3] = { {"张三",1001,18,'M'},{ "李四",1002,18,'M' } ,{ "王二",1003,18,'M' } },temp;

	outFile.open("test.txt", ios_base::out);   
	inFile.open("test.txt", ios_base::in);
	if (!outFile) {
		cerr << "open error!" << endl;
		abort();
	}
	if (!inFile) {
		cerr << "write error!" << endl;
		abort();
	}

	for (int i = 0; i < 3; i++)
	{
		outFile.write((char*)&stu[i], sizeof(Student));
		//outFile << "\n";	//插入换行符
	}
	outFile.close();
	for (int i = 0; i < 3; i++)
	{
		inFile.read((char*)&temp, sizeof(Student));
		cout << temp.age << temp.gender << temp.name << temp.num << endl;
	}
	inFile.close();
	cin.get();
	return 0;
}

打包解包

要想将文件打包生成文件,我们需要一张索引表,索引表里面包括关于文件的信息,例如文件名,文件大小…

索引表之后就是文件内容,假设我有四张图片,需要将四张图片打包生成一个.pack包,并且pack包能够被解开获取里面的内容

首先看一下索引表有什么内容

首先是红色区域,占8个字节,存储索引表的信息,索引表的左边是索引表的大小,右边是文件数量

其次是索引表中包含的文件信息,从左到右依次是文件名大小、文件偏移量,文件大小,文件名

文件偏移量:就是资源文件在打包文件中的位置

C++进阶学习---IO流_编程开发

然后开始关于C++文件操作的打包解包:

#include<iostream>
using namespace std;
#include <fstream>
//索引表大小:4  文件数量:4   文件1大小 文件1偏移  文件1名大小 文件1名  文件2.。。
struct FileInfo
{
	int fileNameSize;	//文件名字大小
	int fileOffset;		//文件的偏移量
	int fileSize;		//文件的大小
	char fileName[20];	//文件名
};
void packFile()
{
	FileInfo fileList[4] = {
		{ 0,0,0,"1.jpg" },
		{ 0,0,0,"2.jpg" },
		{ 0,0,0,"3.jpg" },
		{ 0,0,0,"4.jpg" }
	};
	fstream file[4];

	int listSize = 0;	//索引表大小
	int fileNum = 4;	//文件数量
	for (int i = 0; i < 4; i++)
	{
		fileList[i].fileNameSize = strlen(fileList[i].fileName) + 1;	//1是\0
		listSize += fileList[i].fileNameSize + 12;	//求索引表的大小

		file[i].open(fileList[i].fileName, ios_base::in | ios_base::binary);	//打开文件
		file[i].seekp(0, ios_base::end);					//读指针移动到末尾
		fileList[i].fileSize = file[i].tellp();				//获取文件大小
		file[i].seekp(0, ios_base::beg);					//读指针移动到开头
	}
	//写文件索引信息
	fstream outfile("new.pack", ios_base::out | ios_base::binary);
	outfile.write((char*)&listSize, 4);
	outfile.write((char*)&fileNum, 4);
	//写索引表
	for (int i = 0; i < 4; i++)
	{
		if (i == 0)
			fileList[i].fileOffset = 8 + listSize;
		else
			fileList[i].fileOffset = fileList[i - 1].fileOffset + fileList[i - 1].fileSize;

		outfile.write((char*)&fileList[i].fileNameSize, 4);
		outfile.write((char*)&fileList[i].fileOffset, 4);
		outfile.write((char*)&fileList[i].fileSize, 4);
		outfile.write((char*)&fileList[i].fileName, fileList[i].fileNameSize);
	}
	//写文件
	char ch;
	for (int i = 0; i < 4; i++)
	{
		while (ch = file[i].get(),!file[i].eof())
		{
			outfile.put(ch);
		}
		file[i].close();
	}
	outfile.close();
}
void unPackFile() 
{
	fstream inFile;
	inFile.open("new.pack", ios_base::in | ios_base::binary);
	int listSize;	//索引表大小
	int fileNum;	//文件数量
	//读文件索引信息
	inFile.read((char*)&listSize, 4);
	inFile.read((char*)&fileNum, 4);

	FileInfo* fileList = new FileInfo[fileNum];
	fstream *file = new fstream[fileNum];
	//读索引表
	for (int i = 0; i < fileNum; i++)
	{
		inFile.read((char*)&fileList[i].fileNameSize, 4);
		inFile.read((char*)&fileList[i].fileOffset, 4);
		inFile.read((char*)&fileList[i].fileSize, 4);
		inFile.read((char*)&fileList[i].fileName, fileList[i].fileNameSize);
		file[i].open(fileList[i].fileName, ios_base::out|ios_base::binary);
	}
	
	for (int i = 0; i < fileNum; i++)
	{
		for (int j = 0; j < fileList[i].fileSize; j++)
		{
			file[i].put(inFile.get());
		}
		file[i].close();
	}
	inFile.close();
	delete[] fileList;
	delete[] file;
}
int main()
{
	packFile();
	//unPackFile();
	return 0;
}

需要注意的是怎么写入的怎么读取

fstream outfile("new.pack", ios_base::out | ios_base::binary);//二进制写入
inFile.open("new.pack", ios_base::in | ios_base::binary);	  //二进制读取