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

news2025/5/14 13:22:18

什么是输入输出流

        C++ 的输入输出操作是通过 流(stream) 机制实现的。

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

        使用cin和cout

#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

#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;
}

        文件写入操作

// 写入文件
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();:关闭文件,释放与文件关联的资源。

        文件读取操作

// 读取文件
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

#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;
}

        头文件

#include <iostream>
#include <sstream>

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

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

string input = "42 3.14 hello";
stringstream ss(input);

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

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

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

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 对象初始化
#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"

        默认初始化
#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)时,>> 运算符会尝试将读取到的字符串转换为整数。如果字符串包含有效的整数字符序列,就会成功转换;否则会导致流状态错误。

#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 类型时,>> 运算符会读取直到遇到下一个空白字符为止的字符串。
    #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:显示正号(+)

        格式化数字输出

#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值

cout << fixed << setprecision(3);
cout << "Round to 3 decimal places: " << pi << endl;

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

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

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

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 下推荐)

#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;
}
        头文件
#include <iostream>
#include <locale>

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

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

        设置全局区域设置
locale::global(locale(""));

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

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

        输出宽字符字符串
wcout << L"Hello, World" << endl;

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

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

        封装文件读写成类

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

        封装为 FileManager 类

#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 方法
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方法
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 类,它能让你像操作标准输入输出流(如  cin 和  cout)一样对字符串进行操作,从而 实现字符串和其他数据类型之间的转换  
 
场景:
把字符串转成数字(如 "123" -> 123)
把数字转成字符串(如 3.14 -> "3.14")
        

        字符串 数字转换

#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;
}
        字符串转数字
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当跳板)

        数字转字符串

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()ss2 是 stringstream 对象调用它的 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)

#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;
}

        写入部分

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

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 分别是 p1 和 p2 结构体对象的地址
    • reinterpret_cast<char*> 是 C++ 中的强制类型转换操作符,它将结构体对象的地址转换为 char* 类型。这是因为 write 函数要求第一个参数是 char* 类型的指针,指向要写入的数据的起始地址
  • sizeof(p1) 和 sizeof(p2)sizeof 是 C++ 的一个操作符,用于获取对象或类型所占用的字节数(这里是对象,不是地址)。这里 sizeof(p1) 和 sizeof(p2) 分别表示 p1 和 p2 结构体对象的大小,即要写入文件的字节数。

        读取部分

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,用于存储从文件中读取的数据。

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 结构体对象的 name 和 age 成员。

注:

        结构体的内存布局

        Person 结构体的定义如下:

struct Person
{
    char name[20];
    int age;
};

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

        数据读取过程

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
#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
保存结构体、图像、模型参数等数据

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

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

相关文章

电子电器架构 --- DFMEA设计失效模式和后果分析

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 周末洗了一个澡,换了一身衣服,出了门却不知道去哪儿,不知道去找谁,漫无目的走着,大概这就是成年人最深的孤独吧! 旧人不知我近况,新人不知我过…

Apache SeaTunnel:新一代开源、高性能数据集成工具

Apache SeaTunnel 是一款开源、分布式、高性能的数据集成工具&#xff0c;可以通过配置快速搭建数据管道&#xff0c;支持实时海量数据同步。 Apache SeaTunnel 专注于数据集成和数据同步&#xff0c;主要旨在解决数据集成领域的常见问题&#xff1a; 数据源多样性&#xff1a…

python+selenium+pytest自动化测试chrome driver版本下载

chrome浏览器chromedriver版本下载地址 https://googlechromelabs.github.io/chrome-for-testing/#stable

3.1 WPF使用MaterialDesign的介绍1

MaterialDesignInXAML Toolkit 是一个流行的开源 C# WPF 控件库,它实现了 Google 的 Material Design 规范,让开发者可以轻松创建现代化的 WPF 应用程序界面 Material Design 是一个流行的设计语言,由 Google 开发,旨在帮助开发者构建美观且一致的 UI 界面。对于使用 C# 的…

从 0 到 1 打通 AI 工作流:Dify+Zapier 实现工具自动化调用实战

一、引言&#xff1a;当 AI 遇到工具孤岛 在企业数字化转型的浪潮中&#xff0c;AI 工具的应用早已从单一的对话交互进阶到复杂的业务流程自动化。但开发者常常面临这样的困境&#xff1a;本地开发的 MCP 工具&#xff08;如 ERP 数据清洗脚本、CRM 工单系统 API&#xff09;如…

Spring Boot中`logging.config`配置项的详解及使用说明

以下是Spring Boot中logging.config配置项的详解及使用说明&#xff1a; 1. logging.config 作用 功能&#xff1a;指定自定义日志配置文件的路径&#xff0c;覆盖Spring Boot默认的日志配置。适用场景&#xff1a;当需要深度定制日志行为&#xff08;如输出格式、文件路径、…

相机模型--CMOS和CCD的区别

1--CMOS和CCD的工作原理 CCD&#xff08;Charge Coupled Device&#xff0c;电荷耦合器件&#xff09;&#xff1a; 1. 图像通过光电效应在感光单元中转化为电荷&#xff1b; 2. 每个像素上的电荷被依次“耦合”并传输到芯片的角落&#xff0c;通过一个或几个模拟输出放大器输…

el-date-picker时间范围 赋值报错问题

问题&#xff1a; 点击时间范围组件右边清除图标&#xff0c;点击近6小时会把设置好的时间赋值给时间范围组件 但是出现报错 原因&#xff1a; 尝试对null值进行属性设置操作&#xff1a;修改一个数组的元素&#xff0c;但此时这个数组是null&#xff0c;而不是预期的数组类型…

为啥低速MCU单板辐射测试会有200M-1Ghz的辐射信号

低速MCU&#xff08;如8位或16位单片机&#xff09;单板在辐射测试中出现 200MHz~1GHz的高频辐射信号&#xff0c;看似不合理&#xff0c;但实际上是由多种因素共同导致的。以下是详细原因分析及解决方案&#xff1a; 1.根本原因分析: (1) 时钟谐波与开关噪声 低速MCU的时钟谐…

【音视频】FFmpeg解封装

解封装 复用器&#xff0c;比如MP4/FLV 解复用器&#xff0c;MP4/FLV 封装格式相关函数 avformat_alloc_context(); 负责申请一个AVFormatContext结构的内存,并进行简单初始化avformat_free_context(); 释放该结构里的所有东西以及该结构本身avformat_close_input();关闭解复…

OpenLDAP 管理 ELK 用户

文章目录 一、新建 ELK 相关用户组二、配置 Elasticsearch2.1 修改 elasticsearch.yml 配置2.2 使用 API 接口建立角色和用户映射 三、Kibana 验证用户登录 一、新建 ELK 相关用户组 由于后续要将 LDAP 的用户与 ELK 的角色进行映射&#xff0c;所以需先创建几个以 ELK 的角色…

第十七届“华中杯”大学生数学建模挑战赛题目A题 晶硅片产销策略优化 完整成品 代码 模型 思路 分享

近年来&#xff0c;高纯度晶硅片需求的增长引发了更激烈的市场竞争。晶硅片企业需要在成本控制、利润优化和供需管理之间取得平衡&#xff0c;以提高经营效率和市场竞争力。晶硅片的生产是一个高能耗、高成本的过程&#xff0c;企业效益会受到原材料价格波动、市场需求变化以及…

网络层理解

网络层理解 网络层是 OSI 模型的第三层&#xff0c;主要负责 跨网络的数据传输&#xff0c;核心任务是 路由选择 和 分组转发。 网络层核心功能 网络层关键协议 协议作用示例IP (IPv4/IPv6)数据包路由和寻址192.168.1.1ICMP网络状态检测和错误报告ping、tracerouteOSPF/BGP动…

从Archery到NineData:积加科技驱动数据库研发效能与数据安全双升级

积加科技作为国内领先的企业级数字化解决方案服务商&#xff0c;依托自研的 A4X 数字化平台&#xff08;https://a4x.io/&#xff09;&#xff0c;专注于为全球范围内的视觉物联网&#xff08;IoT&#xff09;设备提供 PaaS/SaaS 服务。致力于运用 AI 技术赋能物联网世界的各类…

开源Midjourney替代方案:企业级AI绘画+PPT生成系统+AI源码

「AI取代设计师&#xff1f;」开源Midjourney替代方案&#xff1a;企业级AI绘画PPT生成系统 ——零代码私有化部署&#xff0c;5倍速出图100%版权合规 设计师行业的危机与机遇 1. 传统设计流程的致命短板 痛点 人工设计 AI系统 单张海报耗时 3小时&#xff08;含反复修改…

2025.04.20【Lollipop】| Lollipop图绘制命令简介

Customize markers See the different options allowing to customize the marker on top of the stem. Customize stems See the different options allowing to customize the stems. 文章目录 Customize markersCustomize stems Lollipop图简介R语言中的Lollipop图使用ggp…

【Harmony】常用工具类封装

文章目录 一&#xff0c;简介二&#xff0c;网络请求工具类2.1、鸿蒙原生http封装2.2、第三方axios封装(需提前下载依赖) 三、录音笔相关工具类3.1、录音封装(录入)3.2、录音封装(放音/渲染)3.3、文件写入封装(针对录音/放音功能) 四、RDB关系型数据库4.1、relationalStore简答…

DCDC芯片,boost升压电路设计,MT3608 芯片深度解析:从架构到设计的全维度技术手册

一、硬件架构解析:电流模式升压 converter 的核心设计 (一)电路拓扑与核心组件 MT3608 采用恒定频率峰值电流模式升压(Boost)转换器架构,核心由以下模块构成: 集成功率 MOSFET 内置 80mΩ 导通电阻的 N 沟道 MOSFET,漏极(Drain)对应引脚 SW,源极(Source)内部接…

Cline 之Plan和Act模式

Cline 提供了 "Plan & Act"双模式开发框架。适用在不同的场景。 一、核心模式理念 通过结构化开发流程提升AI编程效率&#xff0c;采用"先规划后执行"的核心理念。 该框架旨在帮助开发者构建更易维护、准确性更高的代码&#xff0c;同时显著缩短开发…

【中级软件设计师】程序设计语言基础成分

【中级软件设计师】程序设计语言基础成分 目录 【中级软件设计师】程序设计语言基础成分一、历年真题二、考点&#xff1a;程序设计语言基础成分1、基本成分2、数据成分3、控制成分 三、真题的答案与解析答案解析 复习技巧&#xff1a; 若已掌握【程序设计语言基础成分】相关知…