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

什么是輸入輸出流

????????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.pswp.cn/web/77307.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/77307.shtml
英文地址,請注明出處:http://en.pswp.cn/web/77307.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

軟件測評中心如何保障軟件質量與安全性?

軟件測評中心是一個專注于保障軟件質量、穩定性和安全性的專業機構。在整個軟件的生命周期中&#xff0c;它扮演著極其關鍵的角色。它運用科學的方法和嚴格的準則&#xff0c;對軟件進行全面而細致的檢測和評估&#xff0c;確保用戶獲得可靠的保障。 測評核心工作 軟件測評中…

論人際關系發展的階段

朋友關系的建立和發展是一個漸進的過程&#xff0c;通常需要經歷情感積累、信任磨合和價值觀融合等階段。以下是朋友關系發展的詳細階段劃分及核心特征&#xff1a; 一、表層接觸階段&#xff08;社交試探期&#xff09; 核心特征&#xff1a;以信息交換為主&#xff0c;關系停…

網絡IP沖突的成因與解決方案

網絡IP沖突的成因與解決方案 一、IP沖突的常見現象與危害二、IP沖突的常見原因三、6種實用解決方案四、預防IP沖突的4個最佳實踐五、總結 前言 肝文不易&#xff0c;點個免費的贊和關注&#xff0c;有錯誤的地方請指出&#xff0c;看個人主頁有驚喜。 作者&#xff1a;神的孩子…

前端節流、防抖函數

節流 什么是節流&#xff1f; 節流就是同一個事件 一秒鐘他執行了很多次。但是我不想他執行這么多次&#xff0c;我只想讓他執行一次 或者兩次。 那該怎么辦&#xff1f; why baby why 那我想就是他執行的時候 我就設置一個定時器&#xff0c;如果定時器是空的&#xff0c;等會…

LeetCode第171題_Excel表列序號

LeetCode 第171題&#xff1a;Excel表列序號 題目描述 給你一個字符串 columnTitle&#xff0c;表示 Excel 表格中的列名稱。返回 該列名稱對應的列序號。 例如&#xff1a; A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 ...難度 簡單 題目鏈…

基于YOLO與PySide6的道路缺陷檢測系統(源碼)

道路基礎設施的健康狀況直接影響交通安全與城市運營效率。傳統人工巡檢方式存在效率低、覆蓋范圍有限等問題,而基于深度學習的自動化檢測技術為道路缺陷識別提供了創新解決方案。本文介紹一個結合YOLO目標檢測模型與PySide6圖形界面的道路塌陷檢測系統,實現了高效、可視化的缺…

04_jQuery

文章目錄 一、jQuery介紹1.1、jQuery概述1.2、jQuery特點1.3 為什么要用jQuery 二、引入jQuery2.1、直接引入2.2、CDN引入 三、jQuery語法3.1、基本使用3.2、jQuery事件及常用事件方法3.3、jQuery選擇器&#xff08;重點&#xff09;3.3.1、基本選擇器3.3.2、層次選擇器3.3.3、…

Adruino:傳感器及步進電機

一、傳感器* 1、溫濕度傳感器 DHT11它采用專用的數字采集技術和溫濕度傳感器技術&#xff0c;包括一個電阻式感濕元件和NTC測溫元件&#xff0c;并與一個高性能的8位單片機連接。DATA端采用串行接口&#xff08;單線雙向&#xff09;與微控制器進行同步和通信。 DHT11的供電電…

高中數學聯賽模擬試題精選第18套幾何題

在 △ A B C \triangle ABC △ABC 中, A B < A C AB< AC AB<AC, 點 K K K, L L L, M M M 分別是邊 B C BC BC, C A C A CA, A B AB AB 的中點. △ A B C \triangle ABC △ABC 的內切圓圓心為 I I I, 且與邊 B C BC BC 相切于點 D D D. 直線 l l l 經過線段…

ubantu18.04(Hadoop3.1.3)之Spark安裝和編程實踐

說明&#xff1a;本文圖片較多&#xff0c;耐心等待加載。&#xff08;建議用電腦&#xff09; 注意所有打開的文件都要記得保存。 第一步&#xff1a;準備工作 本文是在之前Hadoop搭建完集群環境后繼續進行的&#xff0c;因此需要讀者完成我之前教程的所有操作。 以下所有操…

DCDC芯片,boost升壓電路設計,MT3608 芯片深度解析:從架構到設計的全維度技術手冊

一、硬件架構解析:電流模式升壓 converter 的核心設計 (一)電路拓撲與核心組件 MT3608 采用恒定頻率峰值電流模式升壓(Boost)轉換器架構,核心由以下模塊構成: 集成功率 MOSFET 內置 80mΩ 導通電阻的 N 溝道 MOSFET,漏極(Drain)對應引腳 SW,源極(Source)內部接…

Java 日志:掌握本地與網絡日志技術

日志記錄是軟件開發中不可或缺的一部分&#xff0c;它為開發者提供了洞察應用程序行為、診斷問題和監控性能的手段。在 Java 生態系統中&#xff0c;日志框架如 Java Util Logging (JUL)、Log4j 和 Simple Logging Facade for Java (SLF4J) 提供了豐富的功能。然而&#xff0c;…

上位機知識篇---時鐘分頻

文章目錄 前言 前言 本文簡單介紹了一下時鐘分頻。時鐘分頻&#xff08;Clock Division&#xff09;是數字電路設計中常見的技術&#xff0c;用于將高頻時鐘信號轉換為較低頻率的時鐘信號&#xff0c;以滿足不同模塊的時序需求。它在處理器、FPGA、SoC&#xff08;片上系統&am…

推薦幾個免費提取音視頻文案的工具(SRT格式、通義千問、飛書妙記、VideoCaptioner、AsrTools)

文章目錄 1. 前言2. SRT格式2.1 SRT 格式的特點2.2 SRT 文件的組成2.3 SRT 文件示例 3. 通義千問3.1 官網3.2 上傳音視頻文件3.3 導出文案 4. 飛書妙記4.1 官網4.2 上傳音視頻文件4.3 導出文案4.4 缺點 5. VideoCaptioner5.1 GitHub地址5.2 下載5.2.1 通過GitHub下載5.2.2 通過…

Linux深度探索:進程管理與系統架構

1.馮諾依曼體系結構 我們常見的計算機&#xff0c;如筆記本。我們不常見的計算機&#xff0c;如服務器&#xff0c;大部分都遵守馮諾依曼體系。 截至目前&#xff0c;我們所認識的計算機&#xff0c;都是由?個個的硬件組件組成。 輸入設備&#xff1a;鍵盤&#xff0c;鼠標…

觀察者模式 (Observer Pattern)

觀察者模式(Observer Pattern)是一種行為型設計模式。它定義了一種一對多的依賴關系,讓多個觀察者對象同時監聽某一個主題對象。當主題對象的狀態發生變化時,會自動通知所有觀察者對象,使它們能夠自動更新自己的狀態。 一、基礎 1. 意圖 核心目的:定義對象間的一種一對…

Network.framework 的引入,不是為了取代 URLSession

Network.framework 的引入&#xff0c;不是為了取代 URLSession 如果你感覺 Network.framework 的引入, 可能是為了取代 URLSession, 那你就大錯特錯了&#xff01;這里需要非常準確地區分一下&#xff1a; &#x1f535; Network.framework 不是為了取代 URLSession。 &…

Redis 數據分片三大方案深度解析與 Java 實戰

Redis 數據分片是將數據分散存儲在多個 Redis 實例上的技術&#xff0c;以解決單個 Redis 實例在存儲容量、性能和可用性上的限制。常見的 Redis 數據分片方案包括客戶端分片、代理分片和Redis Cluster&#xff08;集群分片&#xff09;&#xff0c;以下為你詳細介紹&#xff1…

FreeBSD可以不經過windows服務器訪問windows機器上的共享文件嗎?

答案是&#xff1a;當然可以&#xff01; 使用sharity-light 軟件 可以使用sharity-light 軟件&#xff0c;直接不用安裝samba等軟件&#xff0c;直接訪問windows機器上的共享文件。 但是可惜的是&#xff0c;sharity-light在FreeBSD的ports里棄用了。看來是從FreeBSD 8 就開…

主流 LLM 部署框架

主流 LLM 部署框架 框架主要特點適用場景vLLM- 超快推理&#xff08;高吞吐&#xff09; - 動態批處理 - 支持 HuggingFace Transformer - 支持 PagedAttention高并發、低延遲在線推理TGI (Text Generation Inference)- Huggingface官方出品 - 多模型管理 - 支持動態量化 - 支持…