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

news2025/6/8 0:38:58

目录

(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;   // 输入数据到缓冲区,然后从缓冲区读取数据给myInt
    cin >> myLong;  // 缓冲区如果还有数据,直接读取数据给myLong
    cin >> mybuf;   // 缓冲区如果还有数据,直接读取数据给mybuf
    
    cout << "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);  // 然后将缓冲区的剩余数据提取到buf2

    cout << "buf1:" << buf1 << endl;  // buf1:aa
    cout << "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:b

    cin.getline(buf2, 256);  // 然后将缓冲区的剩余数据提取到buf2

    cout << "buf1:" << buf1 << endl;  // buf1:aa
    cout << "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 >> n
        cin.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();
    // 输出:hel

    return 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.普通的cout
    cout << "hello world" << endl;

    // 2.使用类成员函数:对下一次的cout进行格式化输出
    cout.width(10);   // 设置输出的宽度是30
    cout.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;  // 普通输出效果:0x7b

    cout << 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;        //以十六进制形式输出整数a
    cout << "oct:" << setbase(8) << a << endl; //以八进制形式输出整数a

    char 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:173
     China
*****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 time

    return 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; // 865

  string strValue1;
  strValue1 = s.str();
  cout << strValue1 << endl; // 865

  
  s.str(""); // 将stringstream底层管理的string对象设置为""
  // 否则多次转化时,会将结果全部累积在底层string对象中

  s.clear(); // 清空s, 不清空会转化失败

  double d = 12.34;
  s << d;
  s >> sa;
  cout << sa << endl; // 12.34
  string strValue2;
  strValue2 = s.str();
  cout << strValue2 << endl; // 12.34

  return 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;               // 构造方式1
    ostr1 << "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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2403530.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

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

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

Reactor和Proactor

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

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

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

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

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

集成学习三种框架

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

在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;…

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

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

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 提供了一…

【云安全】以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弦图解读 ①内圈连线表示基因和生物过程之间的…

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

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

实现单例模式的常见方式

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

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

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

OpenVINO环境配置--OpenVINO安装

TOC环境配置–OpenVINO安装 本节内容 OpenVINO 支持的安装方式有很多种&#xff0c;每一种操作系统以及语言都有对应的安装方法&#xff0c;在官网上有很详细的教程&#xff1a;   我们可以根据自己的需要&#xff0c;来点选环境配置和安装方法&#xff0c;然后网页会给出正…

黑龙江云前沿服务器租用:便捷高效的灵活之选​

服务器租用&#xff0c;即企业直接从互联网数据中心&#xff08;IDC&#xff09;提供商处租赁服务器。企业只需按照所选的服务器配置和租赁期限&#xff0c;定期支付租金&#xff0c;即可使用服务器开展业务。​ 便捷快速部署&#xff1a;租用服务器能极大地缩短服务器搭建周期…

论文解读:Locating and Editing Factual Associations in GPT(ROME)

论文发表于人工智能顶会NeurIPS(原文链接)&#xff0c;研究了GPT(Generative Pre-trained Transformer)中事实关联的存储和回忆&#xff0c;发现这些关联与局部化、可直接编辑的计算相对应。因此&#xff1a; 1、开发了一种因果干预方法&#xff0c;用于识别对模型的事实预测起…

学习设计模式《十二》——命令模式

一、基础概念 命令模式的本质是【封装请求】命令模式的关键是把请求封装成为命令对象&#xff0c;然后就可以对这个命令对象进行一系列的处理&#xff08;如&#xff1a;参数化配置、可撤销操作、宏命令、队列请求、日志请求等&#xff09;。 命令模式的定义&#xff1a;将一个…

十三、【核心功能篇】测试计划管理:组织和编排测试用例

【核心功能篇】测试计划管理&#xff1a;组织和编排测试用例 前言准备工作第一部分&#xff1a;后端实现 (Django)1. 定义 TestPlan 模型2. 生成并应用数据库迁移3. 创建 TestPlanSerializer4. 创建 TestPlanViewSet5. 注册路由6. 注册到 Django Admin 第二部分&#xff1a;前端…

手撕 K-Means

1. K-means 的原理 K-means 是一种经典的无监督学习算法&#xff0c;用于将数据集划分为 kk 个簇&#xff08;cluster&#xff09;。其核心思想是通过迭代优化&#xff0c;将数据点分配到最近的簇中心&#xff0c;并更新簇中心&#xff0c;直到簇中心不再变化或达到最大迭代次…

SmolVLA: 让机器人更懂 “看听说做” 的轻量化解决方案

&#x1f9ed; TL;DR 今天&#xff0c;我们希望向大家介绍一个新的模型: SmolVLA&#xff0c;这是一个轻量级 (450M 参数) 的开源视觉 - 语言 - 动作 (VLA) 模型&#xff0c;专为机器人领域设计&#xff0c;并且可以在消费级硬件上运行。 SmolVLAhttps://hf.co/lerobot/smolvla…