当前位置: 首页 > article >正文

c++中的输入输出流(标准IO,文件IO,字符串IO)

目录

(1)I/O概述

I/O分类

不同I/O的继承关系

不同I/O对应的头文件

(2)iostream 标准I/O流

iostream头文件中的IO流对象

iostream头文件中重载了<<和>>

缓冲区示意图

标准输入流 cin用法

cin:按空格或者换行符分隔

cin.get():一个一个字符处理

cin.getline 按换行符分隔

cin.ignore 消除缓冲区前n个字符

cin.peek() 判断缓冲区是否有数据

cin.putback(mychar) 将mychar放入缓冲区的最左边

标准输出流 cout 用法

cout.put(mychar) 输出一个字符

cout.write  将字符串的指定长度输出到屏幕上

格式化输出

(3)fstream 文件I/O流

1.文件流类和对象

2.文件读写操作

打开文件

文件打开模式

二元或运算符"|"

读不存在的文件时不会报错,直接跳过

is_open() 检查文件能否打开

good()方法

关闭文件

操作文件例子

3.两种类型文件的读写

C++对ASCII文件的读写操作

C++对二进制文件的读写操作

(4)sstream字符串流用法

1.stringstream

stringstream对象的构造与基础操作

用stringstream和getline分割字符串

用stringstream进行数据类型转换

2.istringstream、ostringstream

3.getline()与cin.getline()函数用法详解

getline()函数

cin.getline用法

4.string字符串类用法

(5)综合应用例子:读取配置文件


(1)I/O概述

I/O分类

C++输入输出包含以下三个方面的内容:

  • 标准I/O:对系统指定的标准设备的输入和输出。一般从键盘输入数据,输出到显示器屏幕。这种输入输出称为标准的输入输出,简称标准I/O。
  • 文件I/O:以外存磁盘文件为对象进行输入和输出,即从磁盘文件输入数据,数据输出到磁盘文件。以外存文件为对象的输入输出称为文件的输入输出,简称文件I/O。
  • 串I/O:对内存中指定的空间进行输入和输出。通常指定一个字符数组作为存储空间(实际上可以利用该空间存储任何信息)。这种输入和输出称为字符串输入输出,简称串I/O。

不同I/O的继承关系

在C语言中,用scanf和printf进行输入输出,往往不能保证所输入输出的数据是可靠的安全的。

在C++的输入输出中,编译系统对数据类型进行严格的检查,凡是类型不正确的数据都不可能通过编译。因此C++的I/O操作是类型安全(type safe)的。

C++通过I/O类库来实现丰富的I/O功能。C++编译系统提供了用于输入输出的iostream类库。i-o-stream,意为输入输出流。

ios是抽象基类,由它派生出istream类和ostream类,两个类名中第1个字母i和o分别代表输入(input)和输出(output)。 istream类支持输入操作,ostream类支持输出操作, iostream类支持输入输出操作。iostream类是从istream类和ostream类通过多重继承而派生的类。

类的继承关系如下:

C++对文件的输入输出需要用ifstream和ofstream类,两个类名中第1个字母i和o分别代表输入和输出,第2个字母f代表文件 (file)。ifstream支持对文件的输入操作, ofstream支持对文件的输出操作。

不同I/O对应的头文件

  • iostream  用于标准I/O操作。
  • fstream  用于文件I/O操作。
  • strstream  用于字符串流I/O。
  • stdiostream  用于混合使用C和C + +的I/O机制时,例如想将C程序转变为C++程序。
  • iomanip  在使用格式化I/O时应包含此头文件。

(2)iostream 标准I/O流

iostream头文件中的IO流对象

在 iostream 头文件中定义的类有 ios,istream,ostream,iostream,istream _withassign, ostream_withassign,iostream_withassign 等。

在iostream头文件中不仅定义了有关的类,还定义了4种流对象

对象

含义

对应设备

对应的类

c语言中相应的标准文件

cin

标准输入流

键盘

istream_withassign

stdin

cout

标准输出流

屏幕

ostream_withassign

stdout

cerr

标准错误流

屏幕

ostream_withassign

stderr

clog

标准错误流

屏幕

ostream_withassign

stderr

在iostream头文件中定义以上4个流对象用以下的形式(以cout为例):

ostream cout(stdout);

在定义cout为ostream流类对象时,把标准输出设备stdout作为参数,这样它就与标准输出设备(显示器)联系起来,如果有

cout << 3;

就会在显示器的屏幕上输出3。

cout流对象

cout是console output的缩写,意为在控制台(终端显示器)的输出。强调几点。

  • cout不是C++预定义的关键字,它是ostream流类的对象,在iostream中定义。
  • 用“cout <<”输出基本类型的数据时,可以不必考虑数据是什么类型,系统会判断数据的类型,并根据其类型选择调用与之匹配的运算符重载函数。而不像C语言中用prinf函数输出不同类型的数据,必须分别指定相应的输出格式符。
  • cout流在内存中对应开辟了一个缓冲区,用来存放流中的数据。当向cout流插入一个endl时,不论缓冲区是否已满,都立即输出流中所有数据,然后插入一个换行符, 并刷新流(清空缓冲区)。注意如果只插人一个换行符”\n“(如cout<<a<<"\n"),则只输出和换行,而不刷新cout 流。

cerr流对象

cerr流对象是标准错误流,cerr流已被指定为与显示器关联。cerr的 作用是向标准错误设备(standard error device)输出有关出错信息。cerr与标准输出流cout的作用和用法差不多。但有一点不同:cout流通常是传送到显示器输出,但也可以被重定向输出到磁盘文件,而cerr流中的信息只能在显示器输出。当调试程序时,往往不希望程序运行时的出错信息被送到其他文件,而要求在显示器上及时输出,这时应该用cerr。cerr流中的信息是用户根据需要指定的。

clog流对象

clog流对象也是标准错误流,它是console log的缩写。它的作用和cerr相同,都是在终端显示器上显示出错信息。区别:cerr是不经过缓冲区,直接向显示器上输出有关信息,而clog中的信息存放在缓冲区中,缓冲区满后或遇endl时向显示器输出。

cout与cerr区别

  • cerr是非缓冲输出流,通过它输出的数据,是不会被缓冲的,也就是你传送一个数据给它,它立即输出,不会延迟。可能是因为这个属性,它常常被用于输出出错信息。也就说错误消息可以直接发送到显示器,而无需等到缓冲区或者新的换行符时,才被显示。一般情况下不被重定向
  • cout流在输出可能会对数据进行缓冲,有时可能还需flush()强制它立即输出数据。cout经过缓冲后输出,默认情况下是显示器。这是一个被缓冲的输出,是标准输出,并且可以重新定向。

iostream头文件中重载了<<和>>

在iostream中只对"<<"和">>"运算符用于标准类型数据的输入输出进行了重载,但未对用户声明的类型数据的输入输出进行重载。如果用户声明了新的类型,并希望用"<<"和">>"运算符对其进行输入输出,按照重运算符重载来做(重载<<参考:【c++】cpp运算符重载_cpp重载运算符-CSDN博客)。

<<和>>本来在C++中是被定义为左位移运算符和右位移运算符的,由于在iostream头文件中对它们进行了重载, 使它们能用作标准类型数据的输入和输出运算符。所以,在用它们的程序中必须用#include命令把iostream包含到程序中。

#include <iostream>
  • >> a表示将数据放入a对象中。
  • << a表示将a对象中存储的数据拿出。

缓冲区示意图

标准输入流 cin用法

cin:按空格或者换行符分隔

调用cin后,首先判断输入缓冲区是否有数据,初始情况下是没有的,如果没有数据,则用户需要输入数据,输入内容后,按回车结束输入。然后输入内容被放在输入缓冲区。

然后cin将从输入缓冲区中取数据时,遇到空格或者换行符就停止。

#include <iostream>
using namespace std;void test1()
{int     myInt;long    myLong;char    mybuf[1024];cin >> myInt;   // 输入数据到缓冲区,然后从缓冲区读取数据给myIntcin >> myLong;  // 缓冲区如果还有数据,直接读取数据给myLongcin >> mybuf;   // 缓冲区如果还有数据,直接读取数据给mybufcout << "myInt:" << myInt << ",myLong:" << myLong << ",mybuf:" << mybuf << endl;/*输入:123 654478 hello world输出:myInt:123,myLong:654478,mybuf:hello*/
}int main()
{// cin基本使用test1();/*判断能否输入成功if (cin >> x) {}一般能成功,所以这里没判断*/return 0;
}

cin.get():一个一个字符处理

示例1:输入一个字符串,读取前面部分字符

#include <iostream>
using namespace std;void test21()
{char a, b, c;cin.get(a);cin.get(b);cin.get(c);cout << a << b << c;
}int main()
{test21();return 0;
}

运行结果

PS D:\BaiduSyncdisk\cpptest> ./main
hello world
hel
PS D:\BaiduSyncdisk\cpptest> ./main

示例2:不断输入一个字符串,循环读取全部字符。如果读到'q',则退出

#include <iostream>
using namespace std;void test22()
{char ch;while ( (ch=cin.get()) != 'q' ){cout << ch;}
}int main()
{// cin.get(): 一次读取一个字符test22();return 0;
}

注意:回车带来的这个换行符也被当做输入的一部分

cin.getline 按换行符分隔
#include <iostream>
using namespace std;// cin.getline(buf, size)函数可以接受空格
void test3()
{char buf1[256];char buf2[256];cin >> buf1;cin.getline(buf2, 256);cout << "buf1:" << buf1 << ",buf2:" << buf2 << endl; 
}int main()
{// cin.getline函数可以接受空格test3();return 0;
}

运行结果

PS D:\BaiduSyncdisk\cpptest> g++ main.cpp -o main
PS D:\BaiduSyncdisk\cpptest> ./main
hello world
buf1:hello,buf2: world
PS D:\BaiduSyncdisk\cpptest>

我们用键盘输入了一个"hello world",首先cin >> buf1;这条语句将空格前的"hello"输入到了buf1,然后剩余部分" world"被输入到了buf2

cin.ignore 消除缓冲区前n个字符
#include <iostream>
using namespace std;// cin.ignore 忽略缓冲区的个数
void test4()
{char buf1[256];char buf2[256];// 请输入一个字符串 含有多个空格 "aa  bb \n cc  dd"cin >> buf1;// 输入"aa  bb \n cc  dd"后,"aa"被输入到了buf1,缓冲区还剩下"  bb \n cc  dd"cin.ignore(2);   // 忽略缓冲区的前2个字符,则"  bb \n cc  dd"变为"bb \n cc  dd"cin.getline(buf2, 256);  // 然后将缓冲区的剩余数据提取到buf2cout << "buf1:" << buf1 << endl;  // buf1:aacout << "buf2:" << buf2 << endl;  // buf2:bb \n cc  dd}int main()
{test4();return 0;
}

cin.peek() 判断缓冲区是否有数据

判断缓冲区是否有数据,若有数据则返回第一个字符

若没有数据则等待用户输入字符串,字符串进入缓冲区,同时返回缓冲区第一个字符

注意缓冲区第一个字符不会被取走,只是返回第一个字符的拷贝

#include <iostream>
using namespace std;void test5()
{char buf1[256];char buf2[256];char mychar;// 请输入一个字符串 含有多个空格 "aa  bb \n cc  dd"cin >> buf1;     // 输入"aa  bb \n cc  dd"后,"aa"被输入到了buf1,缓冲区还剩下"  bb \n cc  dd"cin.ignore(2);   // 忽略缓冲区的前2个字符,"  bb \n cc  dd"变为"bb \n cc  dd"// 查看缓冲区是否有数据mychar = cin.peek();cout << "mychar:" << mychar << endl;   // mychar:bcin.getline(buf2, 256);  // 然后将缓冲区的剩余数据提取到buf2cout << "buf1:" << buf1 << endl;  // buf1:aacout << "buf2:" << buf2 << endl;  // buf2:bb \n cc  dd// 再次查看缓冲区是否有数据,没有会提示输入mychar = cin.peek();cout << "mychar:" << mychar << endl; // mychar:h}int main()
{test5();return 0;
}

运行结果

PS D:\BaiduSyncdisk\cpptest> g++ main.cpp -o main
PS D:\BaiduSyncdisk\cpptest> ./main
aa  bb \n cc  dd
myint:b
buf1:aa
buf2:bb \n cc  dd
hello world
myint:h
PS D:\BaiduSyncdisk\cpptest>

cin.putback(mychar) 将mychar放入缓冲区的最左边

cin.putback(mychar): 将mychar放入缓冲区的最左边

例子:根据输入内容的第一个字符判断是读取数还是字符串

#include <iostream>
using namespace std;void test6()
{cout << "Please, enter a number or a word: ";char c = std::cin.get();  // 输入字符串进缓冲区,然后从缓冲区拿第一个字符// 输入的整数和字符串 分开处理if ( (c >= '0') && (c <= '9') ) {int n; //整数不可能 中间有空格 使用cin >> ncin.putback(c);// cin.putback('9');cin >> n;cout << "You entered a number: " << n << '\n';} else {string str;cin.putback(c);//cin.getline(str);getline(cin, str); // 字符串 中间可能有空格 使用 cin.getline();cout << "You entered a word: " << str << '\n';}}int main()
{test6();return 0;
}

运行结果

PS D:\BaiduSyncdisk\cpptest> g++ main.cpp -o main
PS D:\BaiduSyncdisk\cpptest> ./main
Please, enter a number or a word: 123
You entered a number: 123
PS D:\BaiduSyncdisk\cpptest> ./main
Please, enter a number or a word: hello world
You entered a word: hello world
PS D:\BaiduSyncdisk\cpptest>

标准输出流 cout 用法

cout.put(mychar) 输出一个字符
// cout.put(mychar): 输出一个字符
void test1()
{// cout.put(mychar) 会返回一个cout对象cout.put('h').put('e').put('l');
}int main()
{test1();// 输出:helreturn 0;
}

cout.write  将字符串的指定长度输出到屏幕上
#include <iostream>
#include <cstring>
using namespace std;// cout.write: 将字符串的指定长度输出到屏幕上
void test2()
{char p[128] = "hello itcast";cout.write(p, strlen(p)) << endl;cout.write(p, strlen(p) - 4) << endl;cout.write(p, strlen(p) + 4) << endl;
}int main()
{test2();return 0;
}

运行结果

hello itcast
hello it
hello itcast

格式化输出

例子1

#include <iostream>
#include <cstring>
using namespace std;
#include <iomanip>  // ios::showbase需要// cout.write: 将字符串的指定长度输出到屏幕上
void test3()
{// 1.普通的coutcout << "hello world" << endl;// 2.使用类成员函数:对下一次的cout进行格式化输出cout.width(10);   // 设置输出的宽度是30cout.fill('*');   // 多余位置用*填充cout.setf(ios::showbase); // 显示数进制的基准,比如0x表示16进制cout.setf(ios::internal); // 将填充符号从中间填充cout << hex << 123;       // 将123按照10进制输出// 输出效果:0x******7b,确实是10个宽度cout << endl << endl;cout << hex << 123;  // 普通输出效果:0x7bcout << endl << endl;// 3.使用控制符:对下一次的cout进行格式化输出cout << "<Start>" << setw(10) << setfill('*') << setiosflags(ios::showbase) //基数<< setiosflags(ios::internal)<< hex<< 123<< "<End>\n"<< endl;// 输出效果:<Start>0x******7b<End>,其中0x******7b占用10个宽度
}int main()
{test3();return 0;
}

例子2

#include <iostream>
#include <cstring>
using namespace std;
#include <iomanip>int main()
{int a;cout << "input a:";cin >> a;cout << "dec:" << dec << a << endl;        //以十进制形式输出整数cout << "hex:" << hex << a << endl;        //以十六进制形式输出整数acout << "oct:" << setbase(8) << a << endl; //以八进制形式输出整数achar pt[128] = "China"; //pt指向字符串"China"cout << setw(10) << pt << endl; //指定域宽为,输出字符串cout << setfill('*') << setw(10) << pt << endl; //指定域宽,输出字符串,空白处以'*'填充double pi=22.0/7.0; //计算pi值cout << setiosflags(ios::scientific) << setprecision(8); //按指数形式输出,8位小数cout << "pi=" << pi << endl; //输出pi值cout << "pi=" << setprecision(4) << pi << endl; //按指数形式输出,4位小数cout << "pi=" << setiosflags(ios::fixed) << pi << endl; //改为小数形式输出return 0;
}

运行结果

input a:123
dec:123
hex:7b
oct:173China
*****China
pi=3.14285714e+00
pi=3.1429e+00
pi=0xc.9249249249248p-2

(3)fstream 文件I/O流

1.文件流类和对象

和文件有关系的输入输出类主要在fstream.h这个头文件中被定义,在这个头文件中主要被定义了三个类,由这三个类控制对文件的各种输入输出操 作,他们分别是ifstream、ofstream、fstream,其中fstream类是由iostream类派生而来,他们之间的继承关系见下图所 示。

  • ifstream类,它是从istream类派生的,用来支持从磁盘文件的输入。
  • ofstream类,它是从ostream类派生的,用来支持向磁盘文件的输出。
  • fstream类,它是从iostream类派生的,用来支持对磁盘文件的输入输出。

由于文件设备并不像显示器屏幕与键盘那样是标准默认设备,所以它在fstream.h头文件中是没有像cout这样的预先定义的全局对象,所以我们必须自己定义一个该类的对象。

2.文件读写操作

打开文件

有两种形式

第一种:先创建输出文件流类对象,然后调用该对象的open函数打开文件

ofstream outfile;  //定义ofstream类(输出文件流类)对象outfile
outfile.open("f1.dat", ios::out);  //使文件流与f1.dat文件建立关联

第2行是调用输出文件流的成员函数open打开磁盘文件f1.dat,并指定它为输出文件, 文件流对象outfile将向磁盘文件f1.dat输出数据。ios::out是I/O模式的一种,表示以输出方式打开一个文件。或者简单地说,此时f1.dat是一个输出文件,接收从内存输出的数据。

第二种:在定义文件流对象时指定参数进行构造

在声明文件流类时定义了带参数的构造函数,其中包含了打开磁盘文件的功能,像下面这样。一般多用此形式,比较方便。

ostream outfile("f1.dat",ios::out);

文件打开模式

文件打开模式是决定如何使用文件的设置。openmode 类型定义在一个名为 ios 的流相关类中。这种类型的值是 ios 类的静态常量成员。每个这样的值表示一个标志或一个可以在文件打开时设置的选项。

文件模式标志 含 义

  • ios::app 追加:输出将始终发生在文件的末尾。如果只设置了app则默认也指定out。需trunc没被设定。
  • ios::ate 打开文件后立即定位到文件末尾
  • ios::binary 二进制:读取或写入文件的数据是二进制形式的
  • ios::in 输入:文件将允许输入操作。如果文件不存在,打开将失败。不能是ofstream
  • ios::out 输出:文件将允许输出操作。如果文件不存在,则创建一个给定名称的空文件。不能是ifstream。默认会同时trunc。
  • ios::trunc 截断:如果打开的文件存在,其内容将被丢弃,其大小被截断为零。必须设置了out。

二元或运算符"|"

二元或运算符 | 可以用来结合两个或更多标志的效果。例如,以下打开模式将导致打开的文件既可以输入也可以输出,并且输出最初在文件的末尾进行:

fstream inOutFile;
outFile.open("inout.txt",ios::in | ios::out 丨 ios::ate);

读不存在的文件时不会报错,直接跳过

以下例子运行将不会提示错误

// file: main.cpp#include <iostream>
#include <fstream>
#include <string>using namespace std;int main()
{string filepath = "./xxxxxxxxxxxx.csv";fstream outfile;outfile.open(filepath, ios::in);string line;while (getline(outfile, line)){cout << line << endl;}outfile.close();return 0;
}

is_open() 检查文件能否打开

功能:返回一个布尔值,表示文件流当前是否关联到一个已打开的文件。

返回值:

  • true:文件成功打开。
  • false:文件未打开(可能是路径错误、权限不足、文件不存在等原因)。
 ifstream srcFile("../config/src.json", ios::binary);if (!srcFile.is_open()) {cout << "Fail to open src.json" << endl;return;}

good()方法

在C++的<fstream>库中,ifstream是用于从文件中读取数据的输入文件流。good()方法是istream(ifstream继承自istream)的一个成员函数,用于检查流的状态是否良好。

具体来说,good()函数会返回一个布尔值,表示流是否处于“良好”状态。在以下情况下,流会被认为是“良好”的:

  • 没有到达文件末尾(EOF)。
  • 没有遇到任何其他导致流状态为“坏”或“失败”的情况。

和is_open() 的区别:

  • 检查内容:
    • is_open() 仅检查文件是否成功打开。
    • good() 检查文件流是否处于无错误状态(包括文件结束、读写失败等)。
  • 使用场景:
    • is_open() 通常在文件打开后立即调用,确认文件是否可用。
    • good() 通常在文件操作过程中调用,确认流是否仍可正常读写。
#include <iostream>
#include <fstream>int main() 
{std::ifstream inputFile("example.txt");if (inputFile.is_open()) {std::cout << "文件打开成功。" << std::endl;std::string line;while (inputFile.good()) { // 检查流是否处于良好状态std::getline(inputFile, line);if (inputFile.good()) { // 确保读取成功后再处理std::cout << line << std::endl;}}inputFile.close();} else {std::cerr << "文件打开失败!" << std::endl;}return 0;
}

关闭文件

在对已打开的磁盘文件的读写操作完成后,应关闭该文件。关闭文件用成员函数close。如

outfile.close(); //将输出文件流所关联的磁盘文件关闭

所谓关闭,实际上是解除该磁盘文件与文件流的关联,原来设置的工作方式也失效,这样,就不能再通过文件流对该文件进行输入或输出。此时可以将文件流与其他磁盘文件建立关联,通过文件流对新的文件进行输入或输出。

操作文件例子

读写csv(csv的本质是英文逗号","隔开分列,换行符"\n"分行的字符串)

①文件的写ofstream

#include <iostream>
using namespace std;#include <string>
#include <fstream>int main()
{string csvPath = "./out.csv";ofstream csvfile;csvfile.open(csvPath, ios::out); //打开模式 用app是追加写入// 或者一步到位// ofstream csvfile(csvPath, ios::out);csvfile << "name,age,grade\n";csvfile << "tom," << 12 << "," << 88 << "\n";csvfile << "bob," << 22 << "," << 60 << "\n";csvfile.close();return 0;
}

②文件的读ifstream

#include <iostream>
using namespace std;#include <string>
#include <fstream>int main()
{string csvPath = "./out.csv";// ofstream csvfile;// csvfile.open(csvPath, ios::out);// csvfile << "name,age,grade\n";// csvfile << "tom," << 12 << "," << 88 << "\n";// csvfile << "bob," << 22 << "," << 60 << "\n";// csvfile.close();ifstream inFile("out.csv", ios::in);  string lineStr; while (getline(inFile, lineStr))   // 一行一行读取{// 打印整行字符串  cout << lineStr << endl;}inFile.close();/*// 一个字符一个字符的读char ch;while (inFile.get(ch)) {cout <<ch ;}*/return 0;
}

3.两种类型文件的读写

C++对ASCII文件的读写操作

如果文件的每一个字节中均以ASCII代码形式存放数据,即一个字节存放一个字符,这个文件就是ASCII文件(或称字符文件)。程序可以从ASCII文件中读入若干个字符,也可以向它输出一些字符。

#include <iostream>
using namespace std;
#include "fstream"
#include <cstring>void test1()
{   // 写文件char fname[128] = "./test.txt";ofstream fout(fname, ios::app);  //建立一个输出流对象 和文件关联if (!fout){cout << "open " << fname << " error" << endl;return;}fout << "hello....111" << endl;fout << "hello....222" << endl;fout << "hello....333" << endl;fout.close();// 读文件ifstream fin(fname); //建立一个输入流对象 和文件关联char ch;while (fin.get(ch)) // 一个字符一个字符的读{cout <<ch ;}fin.close();}int main()
{test1();return 0;
}

C++对二进制文件的读写操作

二进制文件不是以ASCII代码存放数据的,它将内存中数据存储形式不加转换地传送到磁盘文件,因此它又称为内存数据的映像文件。因为文件中的信息不是字符数据,而是字节中的二进制形式的信息,因此它又称为字节文件。

在打开时要用ios::binary指定为以二进制形式传送和存储。

对二进制文件的读写主要用istream类的成员函数read和write来实现。这两个成员函数的原型为

istream& read(char *buffer,int len);
ostream& write(const char * buffer,int len);

字符指针buffer指向内存中一段存储空间的首地址。len是读写的字节数,具体读多少字节取决于对象的大小,比如结构体等。调用的方式为:

a.write(p1, 50);
b.read(p2, 30);

上面第一行中的a是输出文件流对象,write函数将字符指针p1所给出的地址开始的50个字节的内容不加转换地写到磁盘文件中。

在第二行中,b是输入文 件流对象,read 函数从b所关联的磁盘文件中,读入30个字节(或遇EOF结束),存放在字符指针p2所指的一段空间内。

例子

#include <iostream>
using namespace std;
#include "fstream"
#include <cstring>class Teacher
{
public:Teacher(){age = 0;strcpy(name, "");}Teacher(int _age, char *_name){age = _age;strcpy(name, _name);}void printT(){cout << "age:" << age << ",name:" << name <<endl;}
protected:
private:int  age;char name[32];
};void test2()
{   // 二进制文件的写char fname[128] = "./test.dat";ofstream fout(fname, ios::binary); //建一个 输出流对象 和文件关联;  if (!fout){cout << "open " << fname << " error" << endl;return ;}Teacher t1(31, (char*)"t31");Teacher t2(32, (char*)"t32");fout.write((char *)&t1, sizeof(Teacher));fout.write((char *)&t2, sizeof(Teacher));fout.close();// 二进制文件的读ifstream fin(fname); //建立一个输入流对象 和文件关联Teacher tmp;fin.read((char*)&tmp, sizeof(Teacher));tmp.printT();fin.read( (char*)&tmp, sizeof(Teacher));tmp.printT();fin.read((char*)&tmp, sizeof(Teacher));tmp.printT();fin.read((char*)&tmp, sizeof(Teacher));tmp.printT();fin.close();// 读取正确个数cout << "----------------"  << endl;ifstream fread(fname); //建立一个输入流对象 和文件关联Teacher temp;while (fread.read((char*)&temp, sizeof(Teacher))){temp.printT();}fread.close();}int main()
{test2();return 0;
}

(4)sstream字符串流用法

1.stringstream

stringstream对象的构造与基础操作

#include <iostream>
#include <string>
#include <sstream> // stringstream 头文件using namespace std;int main()
{string str = "1,2,3,4,5";// 1.构造字符串流对象stringstream ss(str);cout << ss.str() << endl;  // 输出字符串// 2.用多个字符串放入mysstream中stringstream mysstream;mysstream << "first"<< " "<< "second";mysstream << " third times";cout << mysstream.str() << endl; // first second third times// 清空mysstream.str("");// 再次输入mysstream << "one more time";cout << mysstream.str() << endl; // one more timereturn 0;
}

用stringstream和getline分割字符串

#include <iostream>
#include <string>
#include <sstream> // stringstream 头文件
#include <vector>
#include <queue>using namespace std;int main()
{string str = "1,2,3,4,5";cout << str << endl;// 1.将字符串str弄到字符串流ss中stringstream ss(str);// 2.定义一个临时字符串用来不断保存分割后的子串string item;// 3.分割,每调用一次getline就分割一次while (getline(ss, item, ',')) // 用','作为行的分隔符{cout << item << " ";// 对字符串item还可以继续用字符串流操作}return 0;
}

用stringstream进行数据类型转换

#include <iostream>
#include <string>
#include <sstream> // stringstream 头文件using namespace std;int main()
{int a = 865;string sa = "age";// 将一个整形变量转化为字符串,存储到string类对象中stringstream s;s << a;s >> sa;cout << sa << endl; // 865string strValue1;strValue1 = s.str();cout << strValue1 << endl; // 865s.str(""); // 将stringstream底层管理的string对象设置为""// 否则多次转化时,会将结果全部累积在底层string对象中s.clear(); // 清空s, 不清空会转化失败double d = 12.34;s << d;s >> sa;cout << sa << endl; // 12.34string strValue2;strValue2 = s.str();cout << strValue2 << endl; // 12.34return 0;
}

有时需要判断能否输出成功,比如可能会将一个不是整数形式的字符串输出到一个int类型,像下面这样

#include <iostream>
#include <sstream>
#include <string>
using namespace std;int main()
{int x = 10;// 将整数字符串输出到整数类型string line = "xxx";stringstream ssm(line);if (ssm >> x) //判断能否输出成功!!!{/**/}return 0;
}

2.istringstream、ostringstream

C++还引入了ostringstream、istringstream这两个类,要使用他们创建对象就必须包含这个头文件 <sstream>。

  • istringstream类用于执行C++风格的串流的输入操作。istringstream对象可以绑定一行字符串,像输入缓冲区那样。
  • ostringstream类用于执行C风格的串流的输出操作。有时候,我们需要格式化一个字符串,但通常并不知道需要多大的缓冲区。为了保险常常申请大量的缓冲区以防止缓冲区过小造成字符串无法全部存储,这时我们可以考虑使用ostringstream类,该类能够根据内容自动分配内存,并且其对内存的管理也是相当的到位。
#include <iostream>
#include <sstream>
#include <string>
using namespace std;void main01()
{// 1.按空格分隔符,一个一个输出{string str = "h e l l o";istringstream is(str);string s;while (is >> s)cout << "[" << s << "]" << endl;// 输出结果// [h]// [e]// [l]// [l]// [o]}// 2.按空格分隔符,一次性输出完{string str2 = "h e l l o";istringstream is2(str2);string a, b, c, d, e;is2 >> a >> b >> c >> d >> e;cout << a << b << c << d << e << endl;  // hello}// 3.自定义分隔符{string _oline = "EntrustNo,RefNo,StockCode,ExchangeType";istringstream read_l(_oline);string put_l;while (getline(read_l, put_l, ',')){cout << put_l << endl;}// 输出结果// hello// EntrustNo// RefNo// StockCode// ExchangeType}}void main02()
{ostringstream ostr1;               // 构造方式1ostr1 << "hello " << 2012 << endl; // 格式化,此处endl也将格式化进ostr1中cout << ostr1.str();               // hello 2012
}int main()
{// istringstream使用方法main01();// ostringstream使用方法main02();return 0;
}

3.getline()与cin.getline()函数用法详解

getline()函数

getline()函数可以让我们很方便的输入一串字符串。getline()不仅简单,而且安全,因为全局函数 getline() 会帮你处理缓冲区用完之类的麻烦。常见的getline()函数语法有两条:

istream& getline (istream& src, string& buffer, char delim = ‘\n’);

其中的src、buffer、delim的意思分别为

  • src: 进行读入操作的输入流
  • buffer 存储读入的内容
  • delim 终结符,默认 '\n'(换行符)

功能:

  • 将输入流src中读到的字符存入buffer中,直到遇到终结符delim才结束。
  • 函数在输入流src中遇到文件结束符(EOF)或者在读入字符的过程中遇到错误都会结束。
  • 在遇到终结符delim后,delim会被丢弃,不存入line中。在下次读入操作时,将在delim的下个字符开始读入。

例子:输入:get?line()    输出:get

#include<iostream>
#include<string>
using namespace std;int main()
{string line;getline(cin, line, '?');cout<<line;return 0;
}

这里可以不断输入,遇到?才结束输入,即使在?之前随便敲回车都不会结束输入,反而是把回车所代表的换行符当做了输入的内容。

cin.getline用法

getline也可以作为成员函数使用:

cin.getline(char *cha, int num, char f);

向cha中输入num个字符,输入过程中达到num-1个数或者提前遇到f字符,输入结束。

例子:输入hello w?orld    输出hello w;输入hello worl?d    输出hello wor

#include<iostream>
#include<string>
using namespace std;int main()
{char line[100];cin.getline(line, 10, '?');cout<<line;return 0;
}

4.string字符串类用法

参考:C++ stl容器之string(字符串类)-CSDN博客

(5)综合应用例子:读取配置文件

配置文件ClientInfo.csv,每一行用第一个逗号分隔为两部分内容,前一个表示变量名,后一个为值

Appid,562111210,
pwd,123456,
entrust_way,7,
qry_mode,1,
user_mac,MAC:48dabcd2298,
user_ip,IIP:10.56.253.69;LIP:10.34.17.69,

main.cpp

#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;struct ClientInfo
{string account;string password;int qryMode;char entrust_way;string user_mac;string user_ip;
};ClientInfo CI;int s2int(string s)
{stringstream ss1;int d;ss1 << s;ss1 >> d;return d;
}void client_data_receive(string s, struct ClientInfo &CI)  // one line
{int i = 0;istringstream read_l(s);string put_l;string tag;string c;while (getline(read_l, put_l, ',')){if (i == 0){tag = put_l;      } else if (i == 1) { c = put_l;} // 赋值if(tag == "account") {CI.account = c;} else if(tag == "password") {CI.password = c;} else if(tag ==  "qry_mode") {CI.qryMode = s2int(c);         } else if(tag ==  "entrust_way") {CI.entrust_way = c[0];      } else if (tag == "user_mac") {CI.user_mac = c;} else if (tag == "user_ip") {CI.user_ip = c;}i++;}
}void Read_Client_Info()
{char filePath[100] = { "\0" };sprintf(filePath, "%s", "./ClientInfo.csv");ifstream infile;string _oline;infile.open(filePath, ios::in);while (getline(infile, _oline)){client_data_receive(_oline, CI);   // 提取每行数据中需要的信息}}int main()
{// 获取客户信息Read_Client_Info();cout << "[Read_Client_Info] account:"  << CI.account << endl;cout << "[Read_Client_Info] user_mac:"  << CI.user_mac << endl;cout << "[Read_Client_Info] user_ip:" << CI.user_ip.c_str() << endl;return 0;
}


end

相关文章:

c++中的输入输出流(标准IO,文件IO,字符串IO)

目录 &#xff08;1&#xff09;I/O概述 I/O分类 不同I/O的继承关系 不同I/O对应的头文件 &#xff08;2&#xff09;iostream 标准I/O流 iostream头文件中的IO流对象 iostream头文件中重载了<<和>> 缓冲区示意图 标准输入流 cin用法 cin&#xff1a;按空…...

App使用webview套壳引入h5(三)——解决打包为app后在安卓机可物理返回但是在苹果手机无法测滑返回的问题

话不多说&#xff0c;直接放最终版本代码。 解决思路是&#xff1a;如果设备是ios设备在myH5中监听 touchstart 和touchend事件。 经过 App使用webview套壳引入h5的最终代码如下 myApp中&#xff0c;entry.vue代码如下&#xff1a; <template><view class"ent…...

CSS中text-align: justify文本两端对齐

text-align: justify; 是 CSS 中用于控制文本对齐方式的属性值&#xff0c;它的核心作用是让文本两端对齐&#xff08;分散对齐&#xff09;&#xff0c;使段落左右边缘整齐排列。以下是详细解析&#xff1a; 作用效果 均匀分布间距 浏览器会自动调整单词/字符之间的间距&#…...

2025年渗透测试面试题总结-ali 春招内推电话1面(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 ali 春招内推电话1面 一、Web安全核心理解 二、熟悉漏洞及防御方案 三、UDF提权原理与防御 四、XSS Fuzz…...

C#中的依赖注入

1. 依赖注入&#xff08;Dependency Injection, DI&#xff09;概述 定义 &#xff1a;依赖注入是一种设计模式&#xff0c;允许将组件的依赖关系从内部创建转移到外部提供。这样可以降低组件之间的耦合度&#xff0c;提高代码的可测试性、可维护性和可扩展性。 核心思想 &…...

Reactor和Proactor

reactor的重要组件包括&#xff1a;Event事件、Reactor反应堆、Demultiplex事件分发器、Eventhandler事件处理器。...

黄晓明新剧《潜渊》定档 失忆三面间谍开启谍战新维度

据悉&#xff0c;黄晓明领衔主演的谍战剧《潜渊》已于近日正式定档6月9日&#xff0c;该剧以“失忆三面间谍”梁朔为核心&#xff0c;打破传统谍战剧的框架和固有角度&#xff0c;以一种特别的视角将悬疑感推向极致。剧中&#xff0c;梁朔因头部受伤失去记忆&#xff0c;陷入身…...

深入浅出Java ParallelStream:高效并行利器还是隐藏的陷阱?

在Java 8带来的众多革新中&#xff0c;Stream API彻底改变了我们对集合操作的方式。而其中最引人注目的特性之一便是parallelStream——它承诺只需简单调用一个方法&#xff0c;就能让数据处理任务自动并行化&#xff0c;充分利用多核CPU的优势。但在美好承诺的背后&#xff0c…...

物联网嵌入式开发实训室建设方案探讨(高职物联网应用技术专业实训室建设)

一、建设背景与目标 在当今数字化时代&#xff0c;物联网技术正以前所未有的速度改变着人们的生活和工作方式。从智能家居到工业自动化&#xff0c;从智能交通到环境监测&#xff0c;物联网的应用场景无处不在。根据市场研究机构的数据&#xff0c;全球物联网设备连接数量预计…...

集成学习三种框架

集成学习通过组合多个弱学习器构建强学习器&#xff0c;常见框架包括Bagging&#xff08;装袋&#xff09;、Boosting&#xff08;提升&#xff09; 和Stacking&#xff08;堆叠&#xff09; 一、Bagging&#xff08;自助装袋法&#xff09; 核心思想 从原始数据中通过有放回…...

大数据量高实时性场景下订单生成的优化方案

文章目录 一、问题背景二、核心优化目标三、架构设计方案3.1 分层架构设计 3.2 关键组件说明 四、核心优化策略4.1 异步处理与流量控制4.1.1 异步接口设计4.1.2 任务进度查询 4.2 批量处理与并行计算4.2.1 数据分批处理4.2.2 并行流处理 4.3 数据库优化4.3.1 批量插入4.3.2 索…...

在UI界面内修改了对象名,在#include “ui_mainwindow.h“没更新

​原因​&#xff1a;未重新编译UI文件​​ Qt的UI文件&#xff08;.ui&#xff09;需要通过​​uic工具&#xff08;Qt的UI编译器&#xff09;​​生成对应的ui_*.h头文件。如果你在Qt Designer中修改了对象名&#xff0c;但没有​​重新构建&#xff08;Rebuild&#xff09;…...

ocrapi服务docker镜像使用

umiocr只能用于windows&#xff0c;http服务只能找旧版&#xff0c;没办法&#xff0c;只能找docker替代一下了。 umiocr 使用paddleOCR和rapidOCR引擎。以下时这两个docker的运行方法 paddleOCR使用 duolabmeng666的ppocr镜像 镜像大小约2.6G docker run -itd --name ppoc…...

使用React+ant Table 实现 表格无限循环滚动播放

数据大屏表格数据&#xff0c;当表格内容超出&#xff08;出现滚动条&#xff09;时&#xff0c;无限循环滚动播放&#xff0c;鼠标移入暂停滚动&#xff0c;鼠标移除继续滚动&#xff1b;数据量小没有超出时不需要滚动。 *使用时应注意&#xff0c;滚动区域高度父元素高度 - 表…...

Podman 和 Docker

Podman 和 Docker 都是容器化工具&#xff0c;用于创建、运行和管理容器。它们有很多相似之处&#xff0c;但也存在关键区别。下面从多个维度对比它们&#xff0c;并给出适用场景建议。 1. 核心区别 特性DockerPodman守护进程&#xff08;Daemon&#xff09;必须运行 dockerd …...

Neovim - 常用插件,提升体验(三)

文章目录 nvim-treelualineindent-blanklinetelescopegrug-far nvim-tree 官方文档&#xff1a;https://github.com/nvim-tree/nvim-tree.lua 以前我们都是通过 :e 的方式打开一个 buffer&#xff0c;但是这种方式需要记忆文件路径&#xff0c;因此这里可以通过 nvim-tree 插…...

C++单例模式教学指南

C单例模式完整教学指南 &#x1f4da; 目录 [单例模式基础概念][经典单例实现及问题][现代C推荐实现][高级话题&#xff1a;双重检查锁][实战应用与最佳实践][总结与选择指南] 1. 单例模式基础概念 1.1 什么是单例模式&#xff1f; 单例模式&#xff08;Singleton Pattern&…...

SOC-ESP32S3部分:31-ESP-LCD控制器库

飞书文档https://x509p6c8to.feishu.cn/wiki/Syy3wsqHLiIiQJkC6PucEJ7Snib ESP 系列芯片可以支持市场上常见的 LCD&#xff08;如 SPI LCD、I2C LCD、并行 LCD (Intel 8080)、RGB/SRGB LCD、MIPI DSI LCD 等&#xff09;所需的各种时序。esp_lcd 控制器为上述各类 LCD 提供了一…...

如何区分虚拟货币诈骗与经营失败?

首席数据官高鹏律师团队编著 00后大学生杨启超在公有链上发行BFF虚拟币&#xff0c;因在24秒内撤回流动性导致他人损失5万USDT币&#xff0c;被河南南阳法院以诈骗罪判处有期徒刑4年6个月。庭审中&#xff0c;辩护律师手持合约地址记录据理力争&#xff1a;“公有链发币自由、…...

Flink 高可用集群部署指南

一、部署架构设计 1. 集群架构 graph TDClient([客户端]) --> JM1[JobManager 1]Client --> JM2[JobManager 2]Client --> JM3[JobManager 3]subgraph ZooKeeper集群ZK1[ZooKeeper 1]ZK2[ZooKeeper 2]ZK3[ZooKeeper 3]endsubgraph TaskManager集群TM1[TaskManager 1…...

【云安全】以Aliyun为例聊云厂商服务常见利用手段

目录 OSS-bucket_policy_readable OSS-object_public_access OSS-bucket_object_traversal OSS-Special Bucket Policy OSS-unrestricted_file_upload OSS-object_acl_writable ECS-SSRF 云攻防场景下对云厂商服务的利用大同小异&#xff0c;下面以阿里云为例 其他如腾…...

读文献先读图:GO弦图怎么看?

GO弦图&#xff08;Gene Ontology Chord Diagram&#xff09;是一种用于展示基因功能富集结果的可视化工具&#xff0c;通过弦状连接可以更直观的展示基因与GO term&#xff08;如生物过程、分子功能等&#xff09;之间的关联。 GO弦图解读 ①内圈连线表示基因和生物过程之间的…...

青少年编程与数学 02-020 C#程序设计基础 16课题、文件操作

青少年编程与数学 02-020 C#程序设计基础 16课题、文件操作 一、文件操作1. 什么是文件操作&#xff1f;2. 文件操作在程序设计中的重要性小结 二、C#文件操作1. 引入命名空间2. 常见文件操作&#xff08;1&#xff09;创建文件&#xff08;2&#xff09;写入文件&#xff08;3…...

怎么让大语言模型(LLMs)自动生成和优化提示词:APE

怎么让大语言模型(LLMs)自动生成和优化提示词:APE https://arxiv.org/pdf/2211.01910 1. 研究目标:让机器自己学会设计提示词 问题:大语言模型(如GPT-3)很强大,但需要精心设计的“提示词”才能发挥最佳效果。过去靠人工设计提示词,费时费力,还可能因表述差异导致模…...

网关路由配置(Gateway Filters)

- id: system-admin-api # 路由的编号uri: grayLb://system-serverpredicates: # 断言&#xff0c;作为路由的匹配条件&#xff0c;对应 RouteDefinition 数组- Path/admin-api/system/**filters:- RewritePath/admin-api/system/v3/api-docs, /v3/api-docs # 配置&#xff0c;…...

实现单例模式的常见方式

前言 java有多种设计模式&#xff0c;如下图所示&#xff1a; 单例模式它确保一个类只有一个实例&#xff0c;并提供一个全局访问点。 1、单例模式介绍 1.1、使用原因 为什么要使用单例模式&#xff1f; 1. 控制资源访问 核心价值&#xff1a;确保对共享资源&#xff08;如…...

Go 为何天生适合云原生?

当前我们正处在 AI 时代&#xff0c;但是在基础架构领域&#xff0c;仍然处在云原生时代。云原生仍然是当前时代的风口之一。作为一个 Go 开发者&#xff0c;职业进阶的下一站就是学习云原生技术。作为 Go 开发者学习云原生技术有得天独厚的优势&#xff0c;这是因为 Go 天生适…...

数仓面试提问:在资源(计算、存储、人力)受限的情况下,如何优先处理需求并保证核心交付?

在资源受限的情况下高效处理需求并保证核心交付,是每个团队管理者都会面临的挑战。这种既要“少花钱多办事”又要确保关键任务不延误的压力,面对这种情况,我们需要一套系统化的方法来实现需求评估、优先级排序和有效沟通。以下是经过实践验证的策略和方法: 🛠️ 一、 保证…...

第七十四篇 高并发场景下的Java并发容器:用生活案例讲透技术原理

避开快递/电路/医疗案例&#xff0c;聚焦餐厅、超市、影院等生活场景&#xff0c;轻松掌握高并发设计精髓 引言&#xff1a;为什么需要并发容器&#xff1f; 想象一个繁忙的火锅店&#xff1a;30个服务员同时用平板电脑下单。若用普通HashMap记录订单&#xff0c;当两人同时操…...

day20 leetcode-hot100-38(二叉树3)

226. 翻转二叉树 - 力扣&#xff08;LeetCode&#xff09; 1.广度遍历 思路 这题目很简单&#xff0c;就是交换每个节点的左右子树&#xff0c;也就是相当于遍历到某个节点&#xff0c;然后交换子节点即可。 具体步骤 &#xff08;1&#xff09;创建队列&#xff0c;使用广…...