文章目录

  • 1.文件操作
  • 1.1.文件流对象的定义与初始化
  • 1.2.文件流的打开模式
  • 2.内存操作


1.文件操作

1.1.文件流对象的定义与初始化

ios sprintf 头文件 iostream头文件报错_开发语言

  1. 注意ifstream就是basic_ifstream<char>ofstream就是basic_ofstream<char>,因为char类型的更加常用,所以C++中直接就使用char类型实例化了这种模板,并且命名为ifstreamofstream
  2. 简单的实例:注意使用文件流对象需要包含头文件#include <fstream>
#include <iostream>
#include <fstream>  // 文件流头文件
#include <string>

int main()
{
	// 1.输出流,向文件中输出内容
	std::ofstream outFile("my_file");
	outFile << "hello\n";  // 这里和std::cout一样的,只不过这里是输出到文件而非终端
	
	// 2.输入流,把文件中的内容全部读进来
	std::ofstream inFile("my_file");
	std::string x;
	inFile >> x;
	std::cout << x << std::endl;
}
  1. 解释文件流的状态:从上面的实例代码可以看到,无论是输入流还是输出流,初始化的时候都需要和一个文件名的string相绑定,绑定了之后就相当于这个流IO被打开了,注意是流被打开了,而不是文件被打开了。这样就要求一个流IO只能绑定一个文件,不能绑定多个文件,否则就不知道往哪里输入或者输出了。
  2. 文件流与文件的关联:使用文件流的缺省构造函数可以创建一个文件流对象, 但是此时不关联任何文件,也就是此时这个文件流是没有打开的,那么就不能对其进行输入输出操作。可以使用open/close绑定和解绑文件:
// 默认构造函数,不关联任何文件,此时这个流是关闭的
std::ofstream outFile;
// 输出0
std::cout << outFile.is_open() << std::endl;
// 使用open关联文件,同时打开流,可以输出
outFile.open("my_file");
// 输出1
std::cout << outFile.is_open() << std::endl;
// 解绑文件,同时关闭流,关闭输出
outFile.close();
// 输出0
std::cout << outFile.is_open() << std::endl;
  1. 注意文件流对象的析构关闭:当使用close关闭流的时候,会把缓存中的内容写入文件中。但是如果不显示的调用close,在文件流对象销毁的时候,其内部析构函数也会自动调用close关闭流,因此无需显示调用close。如下代码所示,使用{}域来设置文件流对象的生命周期,从而让析构函数自动调用close关闭文件流。
{
	std::ofstream outFile("my_file");
	outFile << "hello\n";
}  // 析构函数自动调用close,缓存内容写入文件中

1.2.文件流的打开模式

  1. 不同文件流有不同的默认打开模式ifstream默认是std::ios_base::inofstream默认是std::ios_base::outfstream默认是std::ios_base::in | std::ios_base::out,注意这个是按位或。
  2. ate与app的异同: 注意ate是打开文件的时候位置位于文件末尾,但是后面可以移动文件流指针到文件的其他地方进行写;但是app只能在文件末尾进行写,而不能移动文件流的指针。
  3. trunc模式:截断文件,可以理解为打开文件后会传入源文件中的内容,然后重新写。
  4. binary模式:禁止系统进行特定的转换,比如换行\n,写入文件之后会被转换成换行到下一行,这就是系统特定的转化。而如果使用binary模式,那么写入的是\n,文件中输出就是\n,不会有系统特定的转换。(注意:可能是这个意思?也可能不对)
  5. 合法的打开方式组合
    注意:注意上面一个很tricky的地方,就是输出流的out模式和out|trunc模式是等价的,也就是如果是out模式,每次打开也会把文件清空然后重新写。因此即使是使用out|ate的模式,结果每次也是打开文件之后先把文件清空,然后把指针放到文件末尾(实际由于文件是空的,此时就是文件开头),这样效果和out是一样的。因此如果想在文件末尾追加内容,那么一定要是用app的模式。

2.内存操作

ios sprintf 头文件 iostream头文件报错_c语言_02

  1. 注意istringstream就是basic_istringstream<char>ostringstream就是basic_ostirngstream<char>,因为char类型的更加常用,所以C++中直接就使用char类型实例化了这种模板,并且命名为istringstreamostringstream
  2. 简单的实例:注意使用内存流需要包含头文件#include <sstream>
#include <iostream>
#include <sstream>

int main()
{
	// 1.输出流
	std::ostringstream obj1;
	obj1 << 1234;  // 写入的是1234的整数,这里使用操作符,因此会进行格式化变成字符
	std::string res = obj1.str();  // 获取obj1对应的内存,是一个字符串
	std::cout << res << std::endl;
	
	// 2.输入流
	std::istringstream obj2(res);  // 初始化的时候要绑定一块内存
	int x;
	obj2 >> x;  // 把内存中的string转成格式化成int
	std::cout << x << std::endl;  // 输出1234
}
  1. 内存流打开模式:注意只有in/out/ate/app四种模式,没有trunc/binary模式。istringstream默认打开方式是inostringstream默认打开模式是out
  2. 使用str()方法获取底层对应的字符串:注意不能连续使用str().c_str()来获取C风格的字符串,以因为str()方法返回的是一个string的右值,如果写成下面的样子,执行完c_res得到的结果是没有问题的,得到了一个指针,但是这个指针是指向右值的,一旦运行到下面的输出语句,右值就被释放了,这个指针就指向一块无效的内存了,这样是非法的。
auto c_res = obj2.str().c_str();
std::cout << c_res << std::endl;
  1. 基于字符串流的字符串拼接操作:如果使用string进行拼接,每次内存不够了都会进行新的内存开辟、拷贝、释放操作,这样性能低。而使用stringstream,由于它内部有缓冲区,而且缓冲区内存比较大,所以一般不会频繁的进行内存开辟、拷贝的操作,所以性能更高。
// 1.性能低的方法
std::string x;
x += "Hello";
x += " world";
x += " Hello";
x += " world";
std::cout << x << std::endl;

// 2.高性能方法
std::ostringstream obj;
obj << "Hello";
obj << " world";
obj << " Hello";
obj << " world";
// 这里调用str()方法一次性把所有内容从缓冲区拷贝到内存中
std::cout << obj.str() << std::endl;