C++ 的 输入输出流(I/O Streams)

什么是输入输出流

C++ 的输入输出操作是通过 **流(stream)**机制实现的。
流------就是数据的流动通道,比如:
输入流:从设备(如键盘、文件)读取数据 → 程序
输出流:程序将数据写入设备(如屏幕、文件)
常用的 I/O 流对象:
头文件 类 说明
<iostream> cin 标准输入流(默认连接键盘)
<iostream> cout 标准输出流(默认连接屏幕)
<iostream> ceer 标准错误流(无缓冲)
<fstream> ifstream 文件输入流
<fstream> ofstream 文件输出流
<fstream> fstream 文件读写流
<sstream> stringstream 字符串流(读写字符串)

使用cin和cout

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
    string name;
    int age;
    cout << "请输入你的名字:";
    cin >> name;
    cout << "请输入你的年龄:";
    cin >> age;
    cout << "你好," << name << ",你今年 " << age << " 岁。" << endl;
    return 0;
}

需要解释的建议转专业;

注意:

cin >> 是以空格为分隔符,遇空格就停止。
如果你想读取带空格的一整行,请用 getline():
getline(cin, name); // 读取整行,包括空格

文件的输入和输出:ifstream/ofstream

cpp 复制代码
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
// 写入文件
    ofstream fout("data.txt");
    fout << "Hello, file!" << endl;
    fout << "C++ 文件操作示例" << endl;
    fout.close();
// 读取文件
    ifstream fin("data.txt");
    string line;
    while (getline(fin, line))
    {
        cout << "读到: " << line << endl;
    }
    fin.close();
    return 0;
}

文件写入操作

cpp 复制代码
// 写入文件
ofstream fout("data.txt");
fout << "Hello, file!" << endl;
fout << "C++ 文件操作示例" << endl;
fout.close();

ofstream fout("data.txt");创建一个 ofstream 对象 fout,并且将其与文件 data.txt 关联起来ofstream 用于向文件写入数据。若文件不存在,会创建该文件;若文件已存在,会清空原有内容。

fout << "Hello, file!" << endl;fout << "C++ 文件操作示例" << endl;:向文件 data.txt 写入两行内容,endl 用于换行。

fout.close();:关闭文件,释放与文件关联的资源。

文件读取操作

cpp 复制代码
// 读取文件
ifstream fin("data.txt");
string line;
while (getline(fin, line))
{
    cout << "读到: " << line << endl;
}
fin.close();

ifstream fin("data.txt");创建一个 ifstream 对象 fin,并将其与文件 data.txt 关联起来ifstream 用于从文件读取数据

string line;:定义一个 string 类型的变量 line,用于存储从文件中读取的每一行内容。

while (getline(fin, line))使用 getline 函数从文件中逐行读取内容每次读取一行并存储到 line 变量中getline 函数在读取到文件末尾时会返回 false,循环结束。

cout << "读到: " << line << endl;:将读取到的每一行内容输出到控制台。

fin.close();:关闭文件,释放与文件关联的资源。

注:在 C++ 里,使用 ofstream 或 ifstream 创建对象时不指定文件打开方式是可行的。

ofstream 默认的打开方式

使用 ofstream 类创建对象并关联文件,却不明确指定打开方式时,ofstream 会采用默认的打开方式。默认情况下,ofstream 以 **ios::out | ios::trunc**模式打开文件。

ios::out:表明以输出模式打开文件,也就是用于向文件写入数据

ios::trunc:意味着如果文件已经存在,会先把文件内容清空,再进行写入操作;若文件不存在,则会创建该文件

手动指定打开方式

若有特殊需求,也能手动指定文件的打开方式。ofstream 类的构造函数可以接收第二个参数,用于指定打开方式

字符串流:stringstream

cpp 复制代码
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
    string input = "42 3.14 hello";
    stringstream ss(input);
    int i;
    double d;
    string s;
    ss >> i >> d >> s;
    cout << "Integer: " << i << ", Float: " << d << ", String: " << s << endl;
    return 0;
}

头文件

cpp 复制代码
#include <iostream>
#include <sstream>

#include <sstream>:该头文件引入了**stringstream 类**,stringstream 类能够将字符串当作流来处理,可进行字符串的输入和输出操作

定义输入字符串并创建 stringstream 对象

cpp 复制代码
string input = "42 3.14 hello";
stringstream ss(input);

string input = "42 3.14 hello"; 定义了一个字符串 input,其中包含一个整数、一个浮点数和一个字符串,它们之间用空格分隔。

stringstream ss(input);创建了一个 stringstream 对象 ss,并将字符串 input 作为初始内容这样 ss 就可以像处理输入流一样处理这个字符串

定义变量并从 stringstream 中提取数据

cpp 复制代码
int i;
double d;
string s;
ss >> i >> d >> s;

int i;double d;string s;:分别定义了一个整数变量 i、一个双精度浮点数变量 d 和一个字符串变量 s用于存储从 stringstream 中提取的数据

ss >> i >> d >> s;:使用**>> 运算符stringstream 对象 ss 中依次提取数据**,并将其存储到对应的变量中。**>> 运算符会根据变量的类型自动进行类型转换**。在这个例子中,它会先将字符串中的第一个整数 "42" 转换为整数类型并存储到 i 中,接着将第二个浮点数 "3.14" 转换为双精度浮点数类型并存储到 d 中,最后将剩余的字符串 "hello" 存储到 s

ids 的顺序不是绝对不能换,交换顺序后,代码的执行结果会依赖于 stringstream 对象 ss 中存储的字符串内容。如果字符串内容的顺序与变量类型的提取顺序不匹配,就可能导致提取失败或者得到不符合预期的结果。

注:

stringstream 类的介绍

stringstream 是 C++ 标准库 <sstream> 头文件中定义的类,它继承自 iostream 类,结合了 istream(输入流)和 ostream(输出流)的功能,允许你像操作文件流或标准输入输出流一样操作字符串。stringstream 主要有以下三个子类:

istringstream:用于从字符串中读取数据,相当于输入流。

ostringstream:用于向字符串中写入数据,相当于输出流。

stringstream:既可以读取也可以写入字符串,兼具前两者的功能。

stringstream 对象的初始化

stringstream 对象不一定 要接受一个 string 类对象来初始化。

使用 string 对象初始化
cpp 复制代码
#include <iostream>
#include <sstream>
#include <string>

int main() {
    std::string input = "42 3.14 hello";
    std::stringstream ss(input);
    return 0;
}

stringstream 对象 ss 被初始化为包含字符串 "42 3.14 hello"

默认初始化
cpp 复制代码
#include <iostream>
#include <sstream>

int main() {
    std::stringstream ss;
    ss << "This is a test";
    return 0;
}

这里先默认初始化了 stringstream 对象 ss,之后可以使用 << 运算符向其写入数据

>> 运算符能从 stringstream 对象中提取对应类型数据的原理

>> 运算符是 C++ 中用于输入流操作的提取运算符。当它用于 stringstream 对象时,其工作原理基于 C++ 的流操作和类型转换机制。

流操作

stringstream 是一个流对象,>> 运算符会从流中读取数据。它会按照空格、制表符或换行符等空白字符来分割流中的内容,每次提取一个 "词"(token)。

类型转换

>> 运算符遇到不同类型的变量时会尝试将读取到的字符串数据转换为该变量的类型。这是通过 C++ 的流库中预定义的类型转换函数实现的

整数类型 :当目标变量是整数类型(如 int)时,>> 运算符会尝试将读取到的字符串转换为整数。如果字符串包含有效的整数字符序列,就会成功转换;否则会导致流状态错误。

cpp 复制代码
#include <iostream>
#include <sstream>

int main() {
    std::string input = "42";
    std::stringstream ss(input);
    int num;
    ss >> num;
    std::cout << "Integer: " << num << std::endl;
    return 0;
}

>> 运算符将字符串 "42" 转换为整数 42 并存储到 num 中。

浮点数和它一样操作;

  • 字符串类型 :当目标变量是 std::string 类型时,>> 运算符会读取直到遇到下一个空白字符为止的字符串。

    cpp 复制代码
    #include <iostream>
    #include <sstream>
    #include <string>
    
    int main() {
        std::string input = "hello world";
        std::stringstream ss(input);
        std::string word;
        ss >> word;
        std::cout << "String: " << word << std::endl;
        return 0;//仅仅输出"hello"
    }

    >> 运算符读取到 "hello" 就停止了,因为遇到了空格,所以 word 被赋值为 "hello"

I/O常见技巧:

读取整行: getline(cin,str)

清除输入缓冲: cin.ignore()或 cin.clear()

判断文件是否打开:fin.is_open()

检查流状态: cin.fail()、fin.eof()

小结

标准流(cin,cout,cerr):控制台输入输出

文件流(ifstream/ofstream/fstream):文件读写

字符串流(stringstream):字符串格式转换

流格式控制:设置小数位、对齐等

C++ 使用 <iomanip> 头文件提供了一系列 格式控制操作符

常见格式控制符:(省略std::)

fixed:使用固定小数位表示法
scientific:科学计数法
setprecision(n):设置小数位保留精度
setw(n):设置输出字符串宽度
left/right/internal:设置对齐方式
setfill(c):设置填充字符
showpos:显示正号(+)

格式化数字输出

cpp 复制代码
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
    double pi = 3.141592653;
    cout << "Default Output: " << pi << endl;
    cout << fixed << setprecision(3);
    cout << "Round to 3 decimal places: " << pi << endl;
    cout << setw(10) << right << setfill('*') << 42 << endl;
    // 右对齐,宽度 10,用 * 填充
    return 0;
}

输出保留三位小数的pi值

cpp 复制代码
cout << fixed << setprecision(3);
cout << "Round to 3 decimal places: " << pi << endl;

cout << fixed << setprecision(3);

fixed 是一个操纵符 ,它会让浮点数以固定点表示法输出,也就是小数点后的位数固定

setprecision(3) 同样是一个操纵符,它指定了输出浮点数时小数点后的位数为 3这两个操纵符结合使用,就能让后续输出的浮点数保留三位小数

右对齐输出整数并填充字符

cpp 复制代码
cout << setw(10) << right << setfill('*') << 42 << endl;

setw(10):这是一个操纵符,它设置了下一个输出项宽度 为 10 个字符。如果输出项的实际宽度小于 10 个字符,就会按照指定的填充字符进行填充。

right:这是一个操纵符,它指定输出项右对齐

setfill('*'):这是一个操纵符,它指定了填充字符为 *

42 是要输出的整数。综合起来,这段代码会以右对齐的方式输出整数 42,宽度为 10 个字符,不足的部分用 * 填充,输出结果为 ********42

中文字符流(UTF-8 / 宽字符)

中文字符通常需要用 **宽字符(wchar_t)+ 宽流(wcout/wcin)**或确保控制台支持 UTF-

8 编码

宽字符流输出中文(Windows 下推荐)

cpp 复制代码
#include <iostream>
#include <locale>
using namespace std;
int main()
{
// 设置全局 locale,使 wcout 能输出中文
//(Windows 使用 "chs" 或 "zh_CN.UTF-8")
    locale::global(locale(""));
    wcout << L"Hello, World" << endl;
    return 0;
}
头文件
cpp 复制代码
#include <iostream>
#include <locale>

#include <iostream>:这是标准输入输出流的头文件,借助它可以使用 coutwcoutcin 等标准输入输出对象。

#include <locale>:该头文件提供了处理区域设置的功能,能让程序适配不同地区的语言、货币、日期格式等

设置全局区域设置
cpp 复制代码
locale::global(locale(""));

locale::global 函数用于设置全局的区域设置

locale("") 代表使用系统默认的区域设置。在 Windows 系统中,这可能会使用**"chs" 或者 "zh_CN.UTF - 8"**,从而确保程序能正确处理中文等宽字符。

输出宽字符字符串
cpp 复制代码
wcout << L"Hello, World" << endl;

wcout用于输出宽字符的****标准输出流对象

L"Hello, World"宽字符字符串,以 L 作为前缀,表明其中的每个字符是宽字符类型(通常是 wchar_t)。

封装文件读写成类

将文件 I/O 封装成类能提升代码复用性与清晰度,特别适合数据处理类

封装为 FileManager 类

cpp 复制代码
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class FileManager
{
public:
    FileManager(const string& fname) : filename(fname) {}
    void writeLine(const string& text)
    {
        ofstream fout(filename, ios::app); // 追加写入
        if (fout.is_open())
        {
            fout << text << endl;
            fout.close();
        }
        else
        {
            cerr << "无法打开文件用于写入!" << endl;
        }
    }
    void readAll() const
    {
        ifstream fin(filename);
        if (fin.is_open())
        {
            string line;
            while (getline(fin, line))
            {
                cout << "读到: " << line << endl;
            }
            fin.close();
        }
        else
        {
            cerr << "无法打开文件用于读取!" << endl;
        }
    }
private:
    string filename;
};
int main()
{
    FileManager file("data.txt");
    file.writeLine("你好,文件!");
    file.writeLine("C++ 文件封装测试。");
    file.readAll();
    return 0;
}
writeLine 方法
cpp 复制代码
void writeLine(const string& text)
{
    ofstream fout(filename, ios::app); // 追加写入
    if (fout.is_open())
    {
        fout << text << endl;
        fout.close();
    }
    else
    {
        cerr << "无法打开文件用于写入!" << endl;
    }
}
  • 功能 :该方法用于向文件中追加一行文本
  • 实现步骤
    1. 创建一个 ofstream 对象 fout,并以**追加模式(ios::app)**打开指定的文件。
    2. 检查文件是否成功打开,如果成功,则将传入的文本 text 写入文件 ,并在末尾添加换行符 endl
    3. 关闭文件流。
    4. 如果文件无法打开,则使用 cerr 输出错误信息(这里也可以换成cout,但cerr本身就是专门用来输出错误信息的。
readall方法
cpp 复制代码
void readAll() const
{
    ifstream fin(filename);
    //上面那一步就等同于:
    //ifstream fin;
    //fin.open(filename);
    //省略掉了使用open()函数
    if (fin.is_open())
    {
        string line;
        while (getline(fin, line))
        {
            cout << "读到: " << line << endl;
        }
        fin.close();
    }
    else
    {
        cerr << "无法打开文件用于读取!" << endl;
    }
}
  • 功能 :该方法用于读取文件中的所有行,并将每行内容输出到控制台
  • 实现步骤
    1. 创建一个**ifstream 对象 fin** ,并打开指定的文件
    2. 检查文件是否成功打开,如果成功,则使用 getline 函数逐行读取文件内容,直到文件结束。
    3. 对于每一行,将其输出到控制台,并在前面加上提示信息 "读到:"。
    4. 关闭文件流。
    5. 如果文件无法打开,则使用 cerr 输出错误信息

注:

cerr和cout的区别

缓冲机制
  • coutcout带有缓冲的输出流。这意味着当你向 cout 输出数据时,数据会先被存储在缓冲区里,等缓冲区满了或者遇到特定的刷新条件(像遇到 endl、调用 flush() 函数或程序结束return 0 的时候直接刷新等),才会将数据输出到对应的设备(一般是控制台)
  • cerrcerr无缓冲的输出流一旦你向 cerr 输出数据,数据会立刻被输出到对应的设备,不会进行缓冲。这种特性使得 cerr 适合用于输出错误信息,因为在程序出错时,你希望错误信息能马上显示出来,而不是等到缓冲区满了才显示。
用途
  • cout :通常用于输出程序的正常运行结果。比如在计算并输出一些数据、显示提示信息等场景下使用。
  • cerr专门用于输出程序运行过程中出现的错误信息。使用 cerr 可以让错误信息和正常输出区分开来,方便调试和监控程序。
输出目标
  • cout :默认情况下,cout 的输出目标标准输出设备,一般是控制台。不过,你可以通过重定向操作将其输出到文件或者其他设备。
  • cerr :默认情况下,cerr 的输出目标标准错误输出设备,同样通常是控制台。和 cout 不同的是,cerr 的输出不会被重定向操作影响,它始终会输出到标准错误输出设备,这样能确保错误信息不会被误重定向到其他地方。

小结

技术点:核心语法/类 场景

格式流控制:<iomanip> 小数精度、对齐、美观输出

中文字符流:wcout,L"",locale 终端/日志中正确输出中文

文件操作封装:自定义类+ifstream/ofstream 实现面向对象的数据存取方式

stringstream 实现类型转换、如何读写二进制文件 (ios::binary)

使用 stringstream 实现类型转换

stringstream 是一个灵活的字符串流工具,能像输入输出流一样操作字符串。

当你创建一个 stringstream 对象后,就可以使用**<< 运算符向这个对象里插入数据**,也能使用 **>> 运算符从这个对象中提取数据**。
主要来自头文件 <sstream> ,这个头文件提供了 stringstream 类,它能让你像操作标准输入输出流(如 cincout)一样对字符串进行操作,从而 实现字符串和其他数据类型之间的转换
场景:
• 把字符串转成数字(如 "123" -> 123)
• 把数字转成字符串(如 3.14 -> "3.14")

字符串**↔**数字转换

cpp 复制代码
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
    string str = "42.5";
    double num;
    stringstream ss(str);
    ss >> num;
    cout << "字符串转数字: " << num << endl;
    int i = 100;
    stringstream ss2;
    ss2 << i;
    string s = ss2.str();
    cout << "数字转字符串: " << s << endl;
    return 0;
}
字符串转数字
cpp 复制代码
string str = "42.5";
double num;
stringstream ss(str);
ss >> num;
cout << "字符串转数字: " << num << endl;
  • stringstream 对象创建与初始化
    • stringstream ss(str);:创建一个 stringstream 对象 ss,并使用字符串 str 对其进行初始化。这意味着 ss 中包含了字符串 "42.5"(这种类似构造函数的初始化只能是字符串类型,不能是int、double等类型,没有对应的构造函数)。
  • 字符串转换为数字
    • ss >> num;:使用输入运算符**>>stringstream 对象 ss 中读取数据,并尝试将其转换为 double 类型** ,然后存储到变量 num 中。这里 "42.5" 被成功转换为 42.5(注意必须用stringstream类型的对象来转化为其他类型的对象,不能直接转化,必须用stringstream当跳板)

数字转字符串

cpp 复制代码
int i = 100;
stringstream ss2;
ss2 << i;
string s = ss2.str();
cout << "数字转字符串: " << s << endl;
  • stringstream 对象创建
    • stringstream ss2;:创建一个空的 stringstream 对象 ss2。(这是因为stringstream类型的对象不能直接被int类型初始化,没有这个构造函数,必须分成两步)
  • 数字写入 stringstream 对象
    • ss2 << i;:使用**输出运算符 <<**将整数 i 的值写入 stringstream 对象 ss2 。此时 ss2 中存储了表示 100 的字符串。
    • 使用 << 运算符将一个 int 类型的变量 i(这里 i 的值为 100)插入到 stringstream 对象 ss2 中时,100 会以++字符串的形式++ 存储在 ss2
  • 获取 stringstream 中的字符串
    • string s = ss2.str();调用 str() 方法stringstream 对象 ss2 中获取存储的字符串,并将其赋值给字符串变量 s

注:

str() 方法的功能

stringstream提供了一个名为**str()成员函数**,其作用是获取 stringstream 对象当前存储的字符串内容。这个方法返回一个 std::string 类型的对象,该对象包含了 stringstream 中存储的所有字符

string s = ss2.str(); 的执行过程

  • 调用 ss2.str()ss2stringstream 对象调用它的 str()方法,会返回一个 std::string 对象,这个对象包含了 ss2 中当前存储的字符串 "100"(100以字符串的形式被存储)。
  • 赋值操作:把 ss2.str() 返回的 std::string 对象赋值给字符串变量 s。经过这一步,变量 s 就存储了 "100" 这个字符串。

替代用法(C++11 起):
• std:: stoi(str) 、std:: stod(str)字符串转 int/double
• std:: to_string(num)数字转字符串
• 但 stringstream 更灵活,可用于复杂结构和格式化场景。

读写二进制文件 (ios::binary)

cpp 复制代码
#include <iostream>
#include <fstream>
using namespace std;
struct Person
{
    char name[20];
    int age;
};
int main()
{
// 写入
    ofstream fout("people.dat", ios::binary);
    Person p1 = {"Alice", 25};
    Person p2 = {"Bob", 30};
    fout.write(reinterpret_cast<char*>(&p1), sizeof(p1));
    fout.write(reinterpret_cast<char*>(&p2), sizeof(p2));
    fout.close();
// 读取
    ifstream fin("people.dat", ios::binary);
    Person p;
    while (fin.read(reinterpret_cast<char*>(&p), sizeof(p)))
    {
        cout << "Name: " << p.name << ", Age: " << p.age << endl;
    }
    fin.close();
    return 0;
}

写入部分

cpp 复制代码
ofstream fout("people.dat", ios::binary);
Person p1 = {"Alice", 25};
Person p2 = {"Bob", 30};
fout.write(reinterpret_cast<char*>(&p1), sizeof(p1));
fout.write(reinterpret_cast<char*>(&p2), sizeof(p2));
fout.close();

ios::binary:是一个文件打开模式标志 ,表示以二进制模式 打开文件。在二进制模式下,数据会以字节形式直接写入文件,不进行额外的字符转换(如换行符转换),这对于存储结构体等二进制数据非常重要。

cpp 复制代码
fout.write(reinterpret_cast<char*>(&p1), sizeof(p1));
fout.write(reinterpret_cast<char*>(&p2), sizeof(p2));
  • fout.write() 是**ofstream 类的成员函数** ,用于将指定数量的字节写入文件
  • reinterpret_cast<char*>(&p1)reinterpret_cast<char*>(&p2)
    • &p1&p2 分别是 p1p2 结构体对象的地址
    • reinterpret_cast<char*> 是 C++ 中的强制类型转换操作符,它将结构体对象的地址转换为 char* 类型。这是因为**write 函数要求****第一个参数是 char* 类型的指针,指向要写入的数据的起始地址**。
  • sizeof(p1)sizeof(p2)sizeof 是 C++ 的一个操作符,用于获取对象或类型所占用的字节数(这里是对象,不是地址)。这里 sizeof(p1)sizeof(p2) 分别表示 p1p2 结构体对象的大小,即要写入文件的字节数。

读取部分

cpp 复制代码
ifstream fin("people.dat", ios::binary);
Person p;
while (fin.read(reinterpret_cast<char*>(&p), sizeof(p)))
{
    cout << "Name: " << p.name << ", Age: " << p.age << endl;
}
fin.close();

定义一个 Person 结构体的对象 p,用于存储从文件中读取的数据。

cpp 复制代码
while (fin.read(reinterpret_cast<char*>(&p), sizeof(p)))
{
    cout << "Name: " << p.name << ", Age: " << p.age << endl;
}
  • fin.read()ifstream 类的成员函数,用于从文件中读取指定数量的字节到指定的内存地址
  • reinterpret_cast<char*>(&p):将 p 结构体对象的地址转换为 char* 类型 ,作为 read 函数的第一个参数,表示读取的数据要存储的起始地址
  • sizeof(p):表示要从文件中读取的字节数,即一个 Person 结构体对象的大小。
  • while (fin.read(...))read 函数在成功读取指定数量的字节时返回 fin 对象本身,在布尔上下文中,fin 对象会被转换为 bool 类型,如果读取成功则为 true,如果遇到文件结束符(EOF)或读取错误则为 false。因此,这个 while 循环会不断读取文件,直到文件结束。
  • 在循环体中,使用 cout 输出从文件中读取的 p 结构体对象的 nameage 成员。

注:

结构体的内存布局

Person 结构体的定义如下:

cpp 复制代码
struct Person
{
    char name[20];
    int age;
};

在内存中,结构体的成员是连续存储的。name 数组占据前 20 个字节,age 这个 int 类型的成员接着存储在 name 之后,一般 int 类型在常见的系统上占 4 个字节。所以,Person 结构体的总大小(sizeof(Person))通常是 24 个字节(20 字节的 name 数组加上 4 字节的 age)。

数据读取过程

cpp 复制代码
Person p;
while (fin.read(reinterpret_cast<char*>(&p), sizeof(p)))
{
    cout << "Name: " << p.name << ", Age: " << p.age << endl;
}
  • 定义一个 Person 结构体的对象 p,用于存储从文件中读取的数据,读出来的数据就存储在了这个定义的p中。
  • reinterpret_cast<char*>(&p):把 p 这个 Person 结构体对象的地址强制转换为 char* 类型。这是因为**read 函数要求第一个参数是 char* 类型的指针**,指向数据要存储的起始地址
  • sizeof(p)确定要从文件中读取的字节数,这里是**Person 结构体的大小**。read 函数会从文件中读取 sizeof(p) 字节的数据,然后把这些数据依次存放到****p 结构体对象****的内存空间里
  • 由于结构体成员在内存中是连续存储的,文件中的前 20 个字节会被存到 p.name 数组中,接下来的 4 个字节会被存到 p.age 中。这样,文件中的二进制数据就和 p 结构体的成员一一对应起来了。

小贴士

写二进制:write(reinterpret_cast<char*>(&obj),sizeof(obj) )

读二进制:read(reinterpret_cast<char*>(&obj),sizeof(obj))

必须用reinterpret_cast因为write/read操作的是char*指针

结构体对齐注意 :添加 #pragma pack(1) 或 alignas(1) 以避免字节填充问题

小结

字符串转数字 stringstream, std::stoi 用户输入处理、配置读取
std::stoi(str)、std::stod(str):字符串转 int/double

cpp 复制代码
#include <iostream>
#include <string>

using namespace std;

int main() {
    string intStr = "123";
    string doubleStr = "3.14";

    int num = stoi(intStr);
    double dNum = stod(doubleStr);

    cout << "字符串 \"" << intStr << "\" 转 int 结果: " << num << endl;
    cout << "字符串 \"" << doubleStr << "\" 转 double 结果: " << dNum << endl;

    return 0;
}    

用法示例;
数字转字符串 stringstream, std::to_string 日志打印、格式化输出
std::to_string(num):数字转字符串
二进制文件读写 ios::binary + write/read
保存结构体、图像、模型参数等数据

相关推荐
zhougl99610 小时前
Java内部类详解
java·开发语言
Grassto10 小时前
11 Go Module 缓存机制详解
开发语言·缓存·golang·go·go module
梵刹古音10 小时前
【C语言】 递归函数
c语言·数据结构·算法
崇山峻岭之间10 小时前
Matlab学习记录41
学习
觉醒大王11 小时前
科研新手如何读文献?从“乱读”到“会读”
论文阅读·笔记·深度学习·学习·自然语言处理·学习方法
代码游侠11 小时前
学习笔记——Linux内核与嵌入式开发3
开发语言·arm开发·c++·学习
yongui4783411 小时前
混凝土二维随机骨料模型 MATLAB 实现
算法·matlab
酉鬼女又兒11 小时前
JAVA牛客入门11~20
算法
怎么没有名字注册了啊11 小时前
C++ 进制转换
开发语言·c++
觉醒大王11 小时前
硕士/博士研究生避坑指南
笔记·深度学习·学习·自然语言处理·职场和发展·学习方法