【C++】万字详解IO流(输入输出流+文件流+字符串流)

这篇具有很好参考价值的文章主要介绍了【C++】万字详解IO流(输入输出流+文件流+字符串流)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言


【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

一、标准输入输出流

流的概念:若干个字节组成的一个字节序列,代表信息从源到目的的流动

头文件 iostream

从标准输入读取流 cin >> //把空格、换行作为分隔符(不读空格)

从标准输出写入流 cout <<

1.1提取符>>(赋值给)与插入符<<(输出到)

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

首先,我们的这个分标题是插入符 << , 这样一看大家是不是都懵了:cin>>a,为什么不是 >> 这个符号是插入符呢?这个不应该是写是插入吗?

请听我娓娓道来:我们将cin理解成写 是从用户的角度理解 因为我们一写 cin 我们就会调用控制台console从黑框中写入东西 所以我们觉得 >> 这个是写 但是cin >> a 的本质是:(注:cin在这里先当作ifstream )我们先从黑框中写入,黑框的数据拷贝给了ifsream流文件:test.txt 接着我们把 test.txt 的文件内容 >> 内存变量,即流向了变量a。总的来说:对于用户调用consolea来说:是写;但是对于文件test.txt流向内存变量:是读(是test.txt赋值给变量a),我们考虑的正是后者!(图片里面的instream写错了,应该是ifstream)

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

理解cin >> a

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

粗暴点讲:我们的cin就是调用键盘然后写入,但是我们的操作符 >> 这个可是提取,提取我们键盘输入的信息

cin >> a :1.调用键盘 2.赋值

理解ifstream(读) >> a

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

把ifstream>>a理解成一个过程 而且这个过程正是cin>>a的第二个过程,我们探讨的数据的流向和键盘与显示器无关,而是探讨数据内存之间的流向

总的来说:

  • 运算符<<常用 做输入输出流的插入符,表明“输出到”,例如 cout<<“Hello”,是把字符串“Hello”输出到屏 幕上
  • 运算符>>常用做提取符,表明“赋值给”,例如:cin>>i,是把键盘输入的信息赋值给i
  • 【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

例子

//应用 
class Stu{
	string name;
	int score;
public:
	Stu(string n="",int s=0){name=n,score=s;}  //构造
	//小羊谨记:写这俩个运算符重载的时候 一定得在返回值和俩个参数都加上引用!
	friend istream& operator>>(istream& in,Stu& s); 
	//声名友元函数  要加关键字friend   friend使得外部函数可以访问
	friend ostream& operator<<(ostream& out,Stu& s);
};

istream& operator>>(istream& in,Stu& s)
{  
	in >> s.name >> s.score;
	return in;
}

ostream& operator<<(ostream& out,Stu& s)
{  
	out << s.name << " " << s.score;
	return out;
}

void test3(){
	Stu s;
	cin>>s;    //但是cin不理解怎么读取Stu型,所以要对cin>>进行重载(详情见上面)
	cout<<s;	
}

1.2get系列函数

  1. get() 函数

    istream& get (char& c);
    
    • getistream 类的成员函数,用于从输入流中获取单个字符。
    • get 只获取一个字符,并且不包括换行符(‘\n’)在内,它不会将换行符留在输入流中。
    • get 函数通常用于从流中获取字符,而不是整行文本。
    • 语法示例:cin.get(character);
  2. getline() 函数

    • getline 也是 istream 类的成员函数,用于从输入流中获取一整行文本。
    • getline 获取整行文本,包括换行符,然后将整行文本存储在字符串中。
    • getline 可以指定一个定界符(默认为换行符’\n’),以指示何时停止读取。
    • 语法示例:cin.getline(str, size);

联系和建议使用情况:

  • 如果你只需要获取单个字符或者有特定需求,那么使用 get 是更合适的选择。
  • 如果你需要获取整行文本,通常用于读取用户输入或从文本文件中读取一行数据,那么使用 getline 更为方便,因为它会一次性获取整行,包括换行符,不需要担心换行符的处理。

get与getline函数细小但又重要的区别

当遇到输人流中的界定符(delim, 即结束字符)时,get()停止执行,但是并不从输入流中提取界定符,直接在字符串缓冲区尾部加结束标志“\0”,从而把界定符放在缓冲区;函数 getline()则相反,它将从输入流中提取界定符,但不会把它存储到结果缓冲区中。

我们先验证get函数最后是\0:

void test()
{
    unsigned char buf1[5];
    cout << "请输入abcde" << endl;
    cin.get((char*)buf1, 5); 
    cout << "get() read: " << buf1 << endl;  
}

因为存放的是一个字符串,因此在4个字符之后要加入一个字符串结束标志,实际上存放到数组中的是5个字符(最后一个是斜杠0)

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

关于定界符缓冲区的问题,我们发现:get写在getline上面,那么回车会被getline接收,导致getline无法进行

但是如果getline写在get上面,会发现回车这个定界符被getline接收了,而不会影响到get

getline在上面:

void test()
{
    unsigned char buf1[10];
    unsigned char buf2[10];

    cin.getline((char*)buf2, 10); 
    cout << "getline() read: " << buf2 << endl;
    
    cin.get((char*)buf1, 10); 
    cout << "get() read: " << buf1 << endl; 
}

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

get在上面:

void test()
{
    unsigned char buf1[10];
    unsigned char buf2[10];
    
    cin.get((char*)buf1, 10); 
    cout << "get() read: " << buf1 << endl; 

    cin.getline((char*)buf2, 10); 
    cout << "getline() read: " << buf2 << endl;
}

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

1.3获取状态信息函数(处理流错误)

获取状态信息的函数如下:

int rdstate(): 无参数,返回值即是状态信息特征值。

  • 0:正确状态 good()
  • 1:系统错误 bad()
  • 2:非法数据读入 fail()
  • 4:到达文件结束,流已经读完 eof()

为什么没有3咧,是因为:在状态函数中,二进制里面只可以有一个1,所以就导致了数字3的不存在

000-0

001-1

010-2

100-4

使用下面函数来检测相应输入输出状态:

  • bool good(): 若返回值 true, 一切正常,没有错误发生。
  • bool bad(): 发生了(或许是物理上的)致命性错误,流将不能继续使用。
  • bool fail(): 若返回值 true,表明I/O 操作失败,主要原因是非法数据(例如读取数字时遇到字母)。但流可以继续使用。
  • bool eof(): 若返回值 true, 表明已到达流的末尾。

要想重置以上成员函数所检查的状态标志,你可以使用成员函数clear(),没有参数。

课本上的例子,例4.4用的是cin.rdstate(),为了避免cin.good()等操作是cin专属这个问题的争议,我这里先不用标准输出输出流,我用istream的另一个文件流来重新命名一个参数进行操作(通过替换txt中文件的值,来达到不同的效果)

例子:检测输入输出状态

void test4_4()
{
	int a;
	ifstream file("D:\\vs code_code\\Teacher_DiXW\\a.txt");
	file >> a;
	cout<<"状态值为:"<<file.rdstate()<<endl;
	if(file.good())
	{
		cout<<" 输入数据的类型正确,无错误!"<<endl;
	}
	
	if(file.fail())
	{
		cout<<" 输入数据类型错误,非致命错误,可清除输入缓冲区挽回!"<<endl;
	}
}

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

接着我们将txt文件从10替换成a,我们继续看看结果:

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

例子:确保一个整型数给变量a

void test4_5()
{
	char BUFF[60];
	int a;
	while(1)
	{
		cin>>a;
		if(cin.fail())
		{
			cout<<"输入有错!请重新输入"<<endl;
			cin.clear();	//清空状态表示位
			cin.get();
			//cin.getline(BUFF,60); //清空流缓冲区
		}
		else
		{
			cout<<a<<endl;
			break;
		}
		
	}
}

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

优化:将get换成getline,就不用有那么多报错信息了,只显示一次提示信息

cin.get() --> cin.getline(BUFF,60);


二、文件输入输出流

2.1文件打开

#include <fstream> 
 		fstream    
ofstream         ifstream              

在fstream类中,成员函数open()实现打开文件的操作,从而将数据流和文件进行关联,通过ofstream,ifstream,fstream对象进行对文件的读写操作

函数:open()

void open (const char* filename, ios_base::openmode mode = ios_base::in);

参数: filename 操作文件名

​ openmode 打开文件的方式

打开文件的方式在ios类(所以流式I/O的基类)中定义,有如下几种方式

ios::in 为输入(读)而打开文件
ios::out 为输出(写)而打开文件
ios::ate 初始位置:文件尾
ios::app 所有输出附加在文件末尾
ios::trunc 如果文件已存在则先清空该文件,若文件不存在则创建文件
ios::binary 二进制方式打开,不做字符转换(别用string 有大bug)

These flags can be combined with the bitwise OR operator (|)

这些方式是能够进行组合使用的,以“或”运算(“|”)的方式:例如

ofstream out;
out.open("Hello.txt", ios::in|ios::out|ios::binary)                 

特别强调以下内容:

很多程序中,可能会碰到ofstream out(“Hello.txt”), ifstream in(“…”),fstream file(“…”)这样的的使用,并没有显式的去调用open()函数就进行文件的操作,直接调用了其默认的打开方式,因为在stream类的构造函数中调用了open()函数,并拥有同样的构造函数,所以在这里可以直接使用流对象进行文件的操作,默认方式如下:

ofstream out("...", ios::out);ifstream in("...", ios::in);fstream file("...", ios::in|ios::out);

当使用默认方式进行对文件的操作时,你可以使用成员函数is_open()对文件是否打开进行验证

2.2关闭文件

当文件读写操作完成之后,我们必须将文件关闭以使文件重新变为可访问的。成员函数close(),它负责将缓存中的数据排放出来并关闭文件。这个函数一旦被调用,原先的流对象就可以被用来打开其它的文件了,这个文件也就可以重新被其它的进程所访问了。为防止流对象被销毁时还联系着打开的文件,析构函数将会自动调用关闭函数close。

2.3文本文件的读写

类ofstream, ifstream 和fstream 是分别从ostream, istream 和iostream 中引申而来的。这就是为什么 fstream 的对象可以使用其父类的成员来访问数据。

一般来说,我们将使用这些类与同控制台(console)交互同样的成员函数(cin 和 cout)来进行输入输出。如下面的例题所示,我们使用重载的插入操作符<<(下面这段代码是写文件):

#include<iostream>
#include<fstream>
using namespace std;
int main ()
{
    ofstream out("D:\\vs code_code\\Teacher_DiXW\\lzy.txt");
    if (out)
    {
        out << "This is a line.\n";
        out << "This is another line.\n";        
    } 
    out.close();
    return 0;
}

测试结果:

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

从文件中读入数据也可以用与 cin>> 的使用同样的方法(下面这段代码是读文件):

#include<iostream>
#include<fstream>
using namespace std;
int main ()
{
    char buffer[256];
    ifstream in("D:\\vs code_code\\Teacher_DiXW\\lzy.txt");
    if (in)
    {
        while(!in.eof())//确保访问到文件末尾
        {
            in.getline(buffer,100);//in >> buffer ;
            cout << buffer << endl;//可以看出 想用ifstream读文件 还是得借助 cout
        }
    }                                   
    return 0;
}

别看小小一段代码,东西可多着呢:首先,我们文件内部的内容是俩行,这就表明如果我们不用eof判断的话,我们读完第一行就结束了;其次,如果我们不用getline,而是用 in >> buffer 那么我们遇到空格就夭折了;最后,我们想要真正的看到结果,还得需要利用cout,这是为了显示在显示器上,文件本身已经有内容了

上面的例子读入一个文本文件的内容,然后将它打印到屏幕上。注意我们使用了一个新的成员函数叫做 eof ,它是ifstream 从类 ios 中继承过来的,当到达文件末尾时返回true 。

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

例子:写文本文件,把学生信息保存到文件当中

#include<fstream>
#include<iostream>
using  namespace  std;
struct STUDENT
{
    char strName[20];
    int nGrade;
};
int main()
{
    ofstream out;
    out.open("D:\\vs code_code\\Teacher_DiXW\\lzy.txt");
    STUDENT st1={"张三",90};
    STUDENT st2={"李四",80};
    out << st1.strName << "\t" << st1.nGrade << endl;
    out << st2.strName << "\t" << st2.nGrade << endl;
    out.close();
    return 0;
}

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

例子:读文本文件并显示在屏幕上

#include<fstream>
#include<iostream>
using  namespace  std;
int main()
{
    char szBuf[80];
    ifstream in("D:\\vs code_code\\Teacher_DiXW\\lzy.txt");
    if(in)
    {
        while(in.getline(szBuf,80))
        {
            cout<<szBuf<<endl;
        }
    }
    in.close();
    return 0;
}

很明显,这个利用getline当作while循环,比上面的eof使用起来更加优秀,而且为什么getline这么写呢?

cin.getline(buff,size);这个的意思就是读取我们键盘给cin的值

那么in.getline(buff,size);这个意思正是将txt文件当中的内容利用getline流向buff

2.4二进制文件

在二进制文件中,使用<< 和>>,以及函数(如getline)来操作符输入和输出数据,没有什么实际意义,虽然它们是符合语法的。

文件流包括两个为顺序读写数据特殊设计的成员函数:write 和 read。第一个函数 (write) 是ostream 的一个成员函数,都是被ofstream所继承。而read 是istream 的一个成员函数,被ifstream 所继承。类 fstream 的对象同时拥有这两个函数。它们的原型是:

write ( char* buffer, streamsize size );

read ( char* buffer, streamsize size );

这里 buffer 是一块内存的地址,用来存储或读出数据。参数size 是一个整数值,表示要从缓存(buffer)中读出或写入的字符数。

例子:写二进制文件

void test_binary_write()
{
	struct Worker w[3]={"zhang",2500,20,"lisi",4500,22,"wang",2500,23};
	ofstream out("D:\\vs code_code\\Teacher_DiXW\\lzy.txt",ios::binary);//后缀表明是二进制文件
	for(int i=0;i<3;i++)
	{
		//out << w[i]; 这么写就成了标准输入输出流了
		out.write((char *) &w[i],sizeof(Worker));   //(要写的数据首地址,要写数据的大小)
	}
	out.close();	 
} 

out.write() 函数用于将指定的二进制数据写入到文件流中。第一个参数是指向要写入的数据的指针,该指针通常需要是 char* 类型,因为 write() 函数按字节处理数据,而 char 类型正好是一个字节。在这里,将 &w[i] 强制转换为 char* 类型,这样就可以将 Worker 类型的数据按字节写入到文件流中。把0X62fd60等变成一个字节的,才可以给write使用!!

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

例子:读二进制文件

void test_binary_read()
{
	//读文件
	ifstream in("D:\\vs code_code\\Teacher_DiXW\\lzy.txt",ios::binary);
	
	Worker temp;
	for(int i=0;i<3;i++)
	{
	 	in.read((char*)&temp,sizeof(Worker));
	 	cout << temp.name <<" "<<temp.wage <<" "<<temp.age <<endl;//放在显示器上
	} 
	in.close();
}

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

将in中的数据内存拷贝给temp,并且每拷贝一个输出一次,循环三次就可以得到我们之前写入文件的全部内容!

二进制文件和普通文件的区别

文本文件与二进制文件的区别_二进制文件和文本文件的区别-CSDN博客

可以看看这篇博客,讲的比较清楚

2.5寻找输入输出流缓冲(这样就可以不用给缓冲区流向数据了)

C++ 标准库封装了一个缓冲区类 streambuf,用于暂存数据。当数据被写入或读取时,它们会先被存储在缓冲区中,然后再被写出或读取到底层设备(如控制台、磁盘文件等)或程序中的变量中。

每个标准 C++ 输入输出流对象都包含一个指向streambuf 的指针,用户可以通过调用rdbuf() 成员函数获得该指针,从而直接访问底层streambuf 对象;可以直接对底层缓冲区进行数据读写,从而跳过上层的格式化输入输出操作。但由于类似的功能均可由上层缓冲区类实现,因此就不再加以论述了。

streambuf 最精彩的部分在于它重载了 operator<< 及 operator>>。这个缓存(buffer)实际是一块内存空间,作为流(stream)和物理文件的媒介。例如,对于一个输出流,每次成员函数put(写一个单个字符)被调用,这个字符不是直接被写入该输出流所对应的物理文件中的,而是首先被插入到该流的缓存(buffer)中。

对 operator<<来说,它以 streambuf 指针为参数,实现把 streambuf对象中的所有字符输出到输出流中;对 operator>>来说,可把输入流对象中的所有字符输入到 streambuf 对象中。

换句话说,对于输出而言:我们可以不需要定义变量从而将内容流向对象再进行输出,我们可以直接输出文件内容

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

void test_read()
{
    ifstream in("D:\\vs code_code\\Teacher_DiXW\\lzy.txt");
    if(in)
    {
        cout << in.rdbuf() < <endl;
    }
    in.close();
}

2.6定位输入输出流

俩个定位函数:

istream&seekg(long relativepos,ios::seek_dir dir)

针对输入流。第一个参数是要移动的字符数目,可正可负;第二个参数是移动方向,是 ios::begin、ios::cur、ios::end 中的一个值。含义是:字符指针相对于移动方向向前或向后 移动了多少个字符。(如果用beg和end的话,第一个参数一般给0就好了)

ostream&seekp(long relativepos,ios::seek_dir dir)

针对输出流。含义同上

流的三个位置标识符:

ios::beg 流开始位置
ios::cur 流指针当前位置
ios::end 流结束位置

例子:先写文件再读文件(用rdbuf读)

#include<fstream>
#include<iostream>
using  namespace  std;
int main()
{
    string a("hello");
    fstream in_out;
    in_out.open("D:\\vs code_code\\Teacher_DiXW\\lzy.txt",ios::in | ios::out | ios::trunc);//trunc保证了没有该文件,则自动创建该文件
    in_out << a;
    //in_out.write("Hello",5);

    in_out.seekg(0,ios::beg);  //读指针移到文件头
    cout<<in_out.rdbuf();
    in_out.close();
    return 0;
}

代码分析:

  1. 正常来说,我们读文件即使用rdbuf读,也得起码用ifstream创建对象,但是如果我们掌握了更改文件指针的定位方法,我们甚至可以写完直接用seekg修改位置输出
  2. 采用了 fstream 输入输出流类,既可读又可写
  3. 注意open 打开标志 ios::in | ios!:out | ios::trunc, 特别是ios::trunc, 它保证了若没有该文件,则自动创建该文件。
  4. 文件打开或创建成功后,文件指针均指向文件头当写完字符串“Hello” 后,文件指针已经偏移了,若想完全显示全部文件内容,必须把指针移到文件头。文中用到了 seekg 函 数,其实用 seekp 函数也是等效的,这是因为fstream 是输入输出流。若是单独的输入流,则 只能用seekg 函数;若是单独的输出流,则只能用 seekp 函数。
  5. 所以在这个代码中一定不可以在写完后就关闭文件,那么就无法修改文件指针了
  6. 同时我们也认识到为什么读文件可以读到全部内容,正是因为文件打开或创建成功后,指向文件头,这个知识点是我之前不懂的

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

我们还可以将seekg用cur重新写:

in_out.seekg(-5,ios::cur);  //读指针移到文件头

效果出来是如出一辙的~


三、字符串输入输出流(理解成动态字符串)

字符串输入输出流类直接对内存而不是对文件和标准输出进行操作,它使用与 cin 及 cout 相同的读取和格式化函数来操纵内存中的数据,所有字符串流类的声明都包含在标准头文件

  • istringstream: 字符串输入流,提供读 string 功能。
  • ostringstream: 字符串输出流,提供写 string 功能。
  • stringstream: 字符串输入输出流,提供读写 string 功能。

利用字符串输入输出流,可以方便地把多种基本数据类型组合成字符串,也可以反解字符串给各种变量赋值。

3.1例子:反解字符串给各变量赋值

void test()
{
    int n;
    float f;
    string str;

    string strText="13.14 hello";

    istringstream s(strText);

    s >> n;//n是int类型
    s >> f;//f是float类型
    s >> str;//str是字符串类型
    cout << "n=" << n << endl;
    cout << "f=" << f << endl;
    cout << "str=" << str << endl;
}

代码分析:

通过字符串输入流 istringstream 读取字符串“13.14 hello”给了s,接着依次赋给整型、浮点型、字符串变量

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

3.2例子:合并不同类型的数据到字符串

void test()
{
    cout<<"输入一个int一个float一个string:";
    int i;
    float f;
    string stuff;

    cin >> i;//输入整形

    cin >> f;//输入float形

    getline(cin,stuff);//输入字符串形

    ostringstream os;
    os << "integer=" << i << endl;
    os << "float=" << f << endl;
    os << "string=" << stuff << endl;

    string result=os.str();
    cout << result << endl;
}

代码分析:

首先分别输入三个变量,并且定义一个 ostringstream 字符串流插入流 使得数据全部流向os 接着利用这俩段代码:

string result=os.str();

cout << result << endl;

很明显,字符串流的读和文件是不同的

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

代码测试结果:

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

3.3例子:字符切割(类3.1)

void test()
{
    //2.用的多的情况 是用来做类型转换 或者 字符切割
    //to_string 数字转换成字符串
    //cout << to_string(1234) << endl;//此时1234是字符串
    istringstream ip("192.168.1.1");//读取
    //要求:拆分ip地址每个数字
    int ipNum[4];//由于这个是int类型的 所以我们在输入的时候无法输入.字符
    for(int i=0;i<4;++i)
    {
        char get_char;
        ip >> ipNum[i];//ip >> ipnum[1] >> ipnum[2] >> ipnum[3] >> ipnum[4]; 
        if(i < 3)//一共三个点
        {
            ip >> get_char;//获取字符
        }
    }
    for(int i=0;i<4;++i)
    {
        cout << ipNum[i] << " ";
    }cout << endl;

}

代码分析:

int ipNum[4];//由于这个是int类型的 所以我们在输入的时候无法输入.字符

if(i < 3)//一共三个点

​ {

​ ip >> get_char;//获取字符

​ }

如果不接收的话,就会使得.无法接收,无法继续进行读取

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

3.4例子:使用stringstream进行类型转换

void test()
{
    stringstream data("");
    int num=12345;
    data << num;//把数据放到流里面 num 给了 data
    
    char result[20]="";
    data >> result;//data给了result
    cout << result;//输出result
}

代码分析:

我们将int类型的 num 流向data,接着定义一个 result 字符数组,我们把data流向字符数组,即可进行类型转换

3.5综合例子:读入每个学生的各科成绩,并显示学生各科成绩及总成绩

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

#include<iostream>
#include<fstream>
#include<sstream>
#include<string>

using namespace std;
int main()
{
    ifstream in("D:\\vs code_code\\Teacher_DiXW\\lzy.txt");//文件以读方式打开
    if(in)
    {
        cout << "打开成功" << endl;
    }
    string strText;
    string strName;//学生姓名
    int nYuwen;//语文成绩
    int nMath;//数学成绩
    int nForeign;//外语成绩
    int nTotal;//总成绩
    while(!in.eof())//while(getline(in,strText)) 这样可以不写eof
    {
        getline(in,strText);//读每行文本数据保存至字符串
        istringstream inf(strText);//把该文本串封装成字符串输入流对象

        inf >> strName >> nYuwen >> nMath >> nForeign;//通过字符串输入流对象

        nTotal=nYuwen+nMath+nForeign;

        cout<<strName<<"\t"<<nYuwen<<"\t"<<nMath<<"\t"<<nForeign<<"\t"<< nTotal<<endl;//给姓名及各成绩赋值
    }
    in.close();
    return 0;
}

代码分析:

首先用 open 函数以读方式打开该文件,然后用 getline 函数一行行读,并且把每行内容存至strText,并把该静态的字符串封装成动态的字符串输入流对象,之后以流的方式给学生姓名及各科成绩赋值,算出总成绩,输出至屏幕

cout << strText;

虽然我们这么写也可以得到结果,但是有一个差异就是这样不会给变量赋值,而且我们的字符串还是静态的

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

方法二:利用文件流+重载输入输出流

#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
using  namespace  std;
class Student
{
    public:
    string strName;//姓名
    int nYuwen;//语文
    int  nMath;//数学
    int nForeign;//外语
};

istream& operator>>(istream& is,Student& s)
{
    is >> s.strName >> s.nYuwen >> s.nMath >> s.nForeign;
    return is;
}

ostream& operator<<(ostream& os,Student& s)
{
    int nTotal=s.nYuwen+s.nMath+s.nForeign;
    os << s.strName << "\t" << s.nYuwen << "\t" << s.nMath << "\t" << s.nForeign <<"\t"<<nTotal<<"\n";
    return os;
}
int main()
{
    ifstream in("D:\\vs code_code\\Teacher_DiXW\\lzy.txt");
    Student s;
    while(!in.eof())
    {
        in >> s;
        cout << s;
    }
    in.close();
    return 0;
}

代码分析:

从面向对象角度来看,方法2更容易扩展和维护,我们将in赋值给s的时候,由于已经重载,所以会用operator >> ;我们将s的数据输出到cout的时候,由于已经重载,所以会用到 operator << !

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

四、总结

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

答案一:哪些流

标准输入输出流、文件输入输出流、字符串输入输出流

答案二:stringstream与其他的区别

stringstream 是 C++ 标准库中的一个类,它是 istringstreamostringstream 的基类。stringstream 类提供了对字符串的输入和输出操作,可以将字符串作为流来处理。

与其他流(ifstreamofstreamistringstreamostringstream)相比,stringstream 最大的区别在于它可以同时进行输入和输出操作。也就是说,可以在同一个 stringstream 对象上进行读取和写入操作。

下面是 stringstream 与其他流的一些不同之处:

  1. 输入和输出:stringstream 可以像其他流一样执行输入和输出操作。你可以使用 << 运算符将数据写入 stringstream,也可以使用 >> 运算符从 stringstream 中读取数据。

  2. 字符串处理:stringstream 主要用于对字符串进行处理。你可以将一个字符串传递给 stringstream 构造函数,也可以通过 str() 方法获取或设置当前的字符串内容。

    stringstream (const string& str,ios_base::openmode which = ios_base::in | ios_base::out);

    str()的返回值:一个字符串对象,包含流缓冲区中当前内容的副本

  3. 数据格式转换:stringstream 提供了方便的数据格式转换功能。你可以使用 << 运算符将不同类型的数据插入到 stringstream 中,然后使用 >> 运算符将其提取出来。这对于将数值类型转换为字符串、字符串解析为数值类型等操作非常有用。

  4. 可变性:stringstream 允许你在同一个对象上进行读写操作,而不需要创建额外的输入流或输出流对象。

总结来说,stringstream 是一个方便的工具,用于在内存中对字符串进行输入和输出操作,并提供了数据格式转换的功能。与其他流相比,它提供了更灵活的读写能力。

答案三:stringstream初始化

  1. 使用默认构造函数初始化:

    std::stringstream ss;  // 默认构造函数创建一个空的 stringstream 对象
    
  2. 使用字符串初始化:

    std::string str = "Hello, World!";
    std::stringstream ss(str);  // 使用字符串来初始化 stringstream 对象
    
  3. 使用字符数组(C 风格字符串)初始化:

    const char* cstr = "Hello, World!";
    std::stringstream ss(cstr);  // 使用字符数组来初始化 stringstream 对象
    
  4. 使用其他 stringstream 对象初始化:

    std::stringstream src_ss("Hello, World!");
    std::stringstream dest_ss(src_ss.str());  // 使用另一个 stringstream 对象的内容来初始化
    

需要注意的是,初始化后的 stringstream 对象可以进行读取和写入操作,可以使用 << 运算符向其中插入数据,也可以使用 >> 运算符从其中提取数据。

以下是一个完整的示例,演示了不同的初始化方式和读写操作:

#include <sstream>

int main() {
    // 初始化 stringstream 对象
    std::stringstream ss("Hello, World!");

    // 写入数据
    ss << " This is a stringstream.";

    // 读取数据并输出
    std::string output;
    ss >> output;
    std::cout << output << std::endl;

    return 0;
}

以上示例将输出:Hello,,它先将 "Hello, World! This is a stringstream." 写入 stringstream 对象,然后使用 >> 运算符提取出第一个字符串 "Hello," 并输出。

通过这些初始化方法,你可以根据需要来创建和初始化 stringstream 对象,并在其上执行相应的读写操作。

答案四:文件流关联文件

  1. 使用构造函数关联文件:

    std::ifstream inputFile("input.txt");  // 以输入模式打开名为 "input.txt" 的文件
    std::ofstream outputFile("output.txt");  // 以输出模式打开名为 "output.txt" 的文件
    
  2. 使用成员函数 open() 关联文件:

    std::ifstream inputFile;
    inputFile.open("input.txt");  // 以输入模式打开名为 "input.txt" 的文件
    
    std::ofstream outputFile;
    outputFile.open("output.txt");  // 以输出模式打开名为 "output.txt" 的文件
    

以上代码示例分别使用 ifstreamofstream 类来关联文件。ifstream 是用于读取文件的输入文件流类,而 ofstream 是用于写入文件的输出文件流类。

在关联文件后,你可以通过文件流对象执行相应的读取和写入操作。例如,对于 ifstream,你可以使用 >> 运算符从文件中读取数据;对于 ofstream,你可以使用 << 运算符将数据写入文件。

答案五:文件流指定文件打开方式

  • std::ios::in:以输入模式打开文件,用于读取文件。(ifstream默认的打开方式)
  • std::ios::out:以输出模式打开文件,用于写入文件。(ofstream默认的打开方式)
  • std::ios::app:在文件末尾追加数据。
  • std::ios::binary:以二进制模式打开文件。
  • std::ios::ate:在打开文件时将文件指针移至文件末尾。
  • std::ios::trunc:如果文件已存在则先清空该文件,若文件不存在则创建文件

可以使用按位或运算符 | 来组合不同的打开模式。例如:

std::ofstream outputFile("output.txt", std::ios::out | std::ios::app);  // 以输出和追加模式打开文件
outputFile.open("output.txt", std::ios::out | std::ios::app);  // 使用 open() 成员函数以输出和追加模式打开文件

答案六:控制流的游标位置

看上述文章2.6

答案七:流的标志位及如何检测

看上述文章1.3

答案八:文件和字符串流读写数据

  1. 文件流读入和写出数据:

    • 读入数据:使用文件流类(如 ifstream)可以从文件中读取数据。

      #include <fstream>
      std::ifstream inputFile("input.txt");  // 打开要读取的文件
      int value;
      if (inputFile >> value) {
          // 读取成功,可以使用读取的值进行后续操作
      } else {
          // 读取失败,处理错误情况
      }
      

      在上述代码中,我们使用 >> 运算符从文件中读取数据,并将其存储在变量 value 中。如果读取成功,则条件为真,可以使用读取的值进行后续操作。如果读取失败(例如遇到非法字符或已达到文件末尾),则条件为假,可以处理错误情况。

    • 写出数据:使用文件流类(如 ofstream)可以向文件中写出数据。

      #include <fstream>
      std::ofstream outputFile("output.txt");  // 打开要写入的文件
      int value = 42;
      if (outputFile << value) {
          // 写入成功
      } else {
          // 写入失败,处理错误情况
      }
      

      在上述代码中,我们使用 << 运算符将数据写入文件。如果写入成功,则条件为真,可以继续执行后续操作。如果写入失败(例如遇到错误或无法写入),则条件为假,可以处理错误情况。

  2. 字符串流读入和写出数据:

    • 读入数据:使用字符串流类 std::stringstream 可以从字符串中读取数据。

      #include <sstream>
      #include <string>
      
      std::string data = "42";
      std::stringstream ss(data);  // 将字符串作为输入源
      
      int value;
      if (ss >> value) {
          // 读取成功,可以使用读取的值进行后续操作
      } else {
          // 读取失败,处理错误情况
      }
      

      在上述代码中,我们将字符串 data 作为输入源创建了一个字符串流 ss。然后,我们使用 >> 运算符从字符串流中读取数据,并将其存储在变量 value 中。读取成功与否的判断和处理错误的方式与文件流类相似。

    • 写出数据:使用字符串流类 std::stringstream 可以将数据写入到字符串中。

      #include <sstream>
      #include <string>
      
      std::stringstream ss;
      
      int value = 42;
      if (ss << value) {
          std::string output = ss.str();  // 将写入的数据转换为字符串
          // 可以使用字符串进行后续操作
      } else {
          // 写入失败,处理错误情况
      }
      

      在上述代码中,我们创建了一个空的字符串流 ss,然后使用 << 运算符将数据写入字符串流中。如果写入成功,则可以通过 str() 函数获取字符串流中的内容,并将其存储在变量 output 中,以便进行后续操作。

通过文件流和字符串流,你可以方便地进行读取和写入操作,无论是从文件还是从字符串中。

答案九:read和write操作

见上述文章2.4

答案十:stringstream的类型转换

见3.4例子

答案十一(对我来说很重要,因为之前用string的时候没有传大小)

  1. char* 缓冲区:

    char buffer[100];
    cin.getline(buffer, 100);
    

    当使用 char* 缓冲区时,你需要提供一个字符数组作为缓冲区,同时还需要指定缓冲区的大小。getline 函数将读取的数据存储到指定的字符数组中。需要注意的是,getline 函数会自动在读取数据时添加空字符 \0 作为字符串的结尾标记。

    区别:

    • char* 缓冲区需要手动指定缓冲区的大小,因此需要确保缓冲区足够大以容纳读取的数据。
    • char* 缓冲区需要提前定义,长度固定,无法动态调整。
  2. string 对象:

    string buffer;
    getline(cin, buffer);//看了博客,发现当初也是这么写的,这个对我来说很不熟练,得多记
    

    当使用 string 对象时,你只需要创建一个空的 string 对象作为缓冲区即可。getline 函数将读取的数据存储到这个 string 对象中。

    区别:

    • string 对象不需要手动指定缓冲区的大小,它可以根据读取的数据自动调整大小
    • string 对象可以方便地进行字符串操作,如获取字符串长度、连接字符串等。

无论使用 char* 缓冲区还是 string 对象作为 getline 函数的参数,其功能和用法是一样的。选择使用哪种类型的缓冲区取决于你的具体需求和编程习惯。如果你需要更灵活和方便的字符串操作,建议使用 string 对象;如果你已经有一个固定大小的字符数组,并且不需要频繁改变缓冲区的大小,那么可以使用 char* 缓冲区。

答案十二:class私有怎么重载

用友元

//小羊谨记:写这俩个运算符重载的时候 一定得在返回值和俩个参数都加上引用!
	friend istream& operator>>(istream& in,Stu& s); 
	//声名友元函数  要加关键字friend   friend使得外部函数可以访问
	friend ostream& operator<<(ostream& out,Stu& s);

【C++】万字详解IO流(输入输出流+文件流+字符串流),小阳c++专栏,c++,开发语言

答案十三:如何访问流的缓冲区

C++ 中的流对象(如 cincout等)都有自己的缓冲区,用于暂存数据。当数据被写入或读取时,它们会先被存储在缓冲区中,然后再被写出或读取到底层设备(如控制台、磁盘文件等)或程序中的变量中。

如果你需要访问流中的缓冲区,可以使用流对象的 rdbuf() 函数来获取指向缓冲区的指针。rdbuf() 函数返回一个指向 streambuf 对象的指针,streambuf 类是 C++ 中处理输入输出缓冲区的基类。通过这个指针,你可以直接访问缓冲区,例如获取缓冲区中的数据、向缓冲区中添加数据等。

见上述文章2.5文章来源地址https://www.toymoban.com/news/detail-759296.html

到了这里,关于【C++】万字详解IO流(输入输出流+文件流+字符串流)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 万字长文·通俗易懂·一篇包掌握——输入/输出·文件操作(c语言超详细系列)(二)

    前言:Hello,大家好😘,我是心跳sy,上一节我们主要学习了格式化输入输出的基本内容,这一节我们对格式化进行更加深入的了解,对文件概念进行介绍,并且对输入、输出与文件读写的基本概念进行学习,本节主要对printf,scanf深入了解,并介绍文件处理函数,如fprintf,

    2024年02月13日
    浏览(63)
  • 如何在云电脑串流中实现声音输入输出—虚拟声卡(虚拟扬声器和虚拟麦克风)开发

    虚拟声卡(虚拟扬声器和虚拟麦克风)技术原理简介 近些年云计算的发展可谓是势不可挡,无论是办公还是娱乐等行业都开始使用云计算来逐步替代直接使用本地物理硬件的技术,例如: 服务器部署。相比之前,现在部署一个服务器都非常简单;我们只需要在阿里云,华为

    2024年02月04日
    浏览(55)
  • 【C语言】getchar和putchar函数详解:字符输入输出的利器

    目录 📌getchar函数 ▪️ 函数原型: ▪️ 目的: ▪️ 返回值: ▪️ 用法: 📌putchar函数 ▪️ 函数原型: ▪️ 目的: ▪️ 参数: ▪️ 返回值: ▪️用法: 📌实例 ▪️ 输入密码并确认流程 📌总结 getchar 和 putchar 是两个标准 C 库函数,用于 C 编程中的输入和输

    2024年02月16日
    浏览(40)
  • 【C语言趣味教程】(8) 标准 IO 流:输入和输出 | 标准输入 stdin | 标准输出 stdout | 详解 printf 和 scanf | 探讨 scanf 缓冲区问题和安全性问题

        🔗 《C语言趣味教程》👈 猛戳订阅!!! 0x00 引入:I/O 的概念 计算机中的输入和输出,简称 ,其中:  代表 Input,即输入。

    2024年02月09日
    浏览(49)
  • C++输入输出和文件

    streambuf 类为缓冲区提供了内存,并提供了用于填充缓冲区、访问缓冲区内容、刷新缓冲区和管理缓冲区内存的类方法; ios_base 类表示流的一般特征,如是否可读取、是二进制流还是文本流等; ios 类基于ios_base,其中包括了一个指向streambuf对象的指针成员; ostream 类是从ios类

    2024年02月01日
    浏览(43)
  • C++学习笔记——输入、输出和文件

    目录 一、标准输入输出 2.1下面是它们的基本用法 解释 二、格式化输入输出 2.2下面是一个示例 解释 三、文件读写 3.3下面是一个文件读写的示例 解释 四、异常处理和错误检测 4.1下面是一个示例 解释 五、一个实例代码 5.1如何读取 CSV 文件,并计算每一列的平均值 上一篇文

    2024年02月01日
    浏览(45)
  • C++文件输入输出的简单实现(Debug)

            文件输入输出是个很有用的东西,有时比赛时要有:要求使用文件输入输出,还有时候……         遇到这种时间限制非常恶心的题目:手动测试会有误差……         文件输入输出 是个很好的选择!         C语言的写法有点复杂,涉及文件指针,本文不多介

    2024年02月19日
    浏览(37)
  • C++学习第二十天----简单文件输入/输出

    1.写入到文本文件中         必须声明自己的ofstream对象,为其命名,并将其同文件关联起来;         方法open()接受一个c-风格字符换作为参数,可以是一个字面字符串,也可以是存在数组中的字符串。         声明一个ofstream对象并将其同文件关联起来后,用于

    2024年02月11日
    浏览(40)
  • JAVA学习:IO流篇(输入输出流)

    输入:将文件以数据流的形式读取到java程序中 输出:通过java程序将数据流写入文件中 按照方向分,可以分为输入流和输出流。 按照单位分,可以分为字节流和字符流,字节流是指每次处理的数据以字节为单位,字符流是指每次处理的数据以字符为单位。 按照功能分,可以

    2023年04月16日
    浏览(39)
  • C++文件操作基础 读写文本、二进制文件 输入输出流 文件位置指针以及随机存取 文件缓冲区以及流状态

    文本文件一般以行的形式组织数据。 包含头文件: #include fstream 类: ofstream(output file stream) ofstream 打开文件的模式(方式):类内open()成员函数参数2.参数1是文件存储/创建路径 例如:fout.open(filename,ios::app); 对于 ofstream,不管用哪种模式打开文件,如果文件不存在,都会创

    2024年01月25日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包