C++修煉:IO流

?????????Hello大家好!很高興我們又見面啦!給生活添點passion,開始今天的編程之路!

我的博客:<但凡.

我的專欄:《編程之路》、《數據結構與算法之美》、《C++修煉之路》、《Linux修煉:終端之內 洞悉真理》

感謝你打開這篇博客!希望這篇博客能為你帶來幫助,也歡迎一起交流探討,共同成長。

目錄

1、C++中的IO庫

2、IO流狀態

3、管理輸出緩沖區

4、標準IO流? ? ? ??

5、文件IO流

6、string IO流


?

1、C++中的IO庫

? ? ? ? C++不僅支持從控制臺讀取數據,還支持從設備中讀取數據和向設備中寫入數據的IO操作,設備可以是文件、控制臺窗口等。?

? ? ? ? C++中的IO庫是通過一個龐大的繼承體系來實現的。這個套體系包含了標準IO流,文件IO流,stringIO流等等。也就是說,我們之前使用的都是標準IO流,從控制臺讀取字符。但實際上還支持從文件讀取,對string字符串,對寬字符進行IO操作。

?

2、IO流狀態

? ? ? ? 在IO的過程中可能會出現各種錯誤,IO流對象中給了四種狀態標識錯誤。?? ? ??

? ? ? ? ?默認都是good狀態,eofbit表示讀到了文件末尾,badbit表示系統級錯誤,如不可恢復的讀寫錯誤,通常情況下,badbit?旦被設置了,流就無法再使用了。failbit表示?個邏輯錯誤,如期望讀取?個整形,但是卻讀取到?個字符,failbit被設置了,流是可以恢復的,恢復以后可以繼續使用。

? ? ? ? 我們在cin變量的時候,如果我們的變量是int類型,但是我們輸入的是一個字符,那么這時候就會標識為failbit:

#include<iostream>
using namespace std;int main()
{int i = 0;cin >> i;//輸入一個字符cout << cin.good() << endl;cout << cin.eof() << endl;cout << cin.fail() << endl;cout << cin.bad() << endl;return 0;
}

輸出結果:

?

? ? ? ? 那么這個時候,我們就得想辦法恢復狀態:

#include <iostream>
using namespace std;int main() {int i = 0;cin >> i; // 輸入一個字符(比如 'x1')cout << cin.good() << endl;  // 0(false)cout << cin.eof() << endl;   // 0(false)cout << cin.fail() << endl;  // 1(true)cout << cin.bad() << endl;   // 0(false)if (cin.fail()) {cin.clear(); // 必須先清除錯誤狀態,否則后續操作無效// 清除所有非數字字符(包括換行符)char ch;while (cin.get(ch) && !(ch >= '0' && ch <= '9')) {cout << ch;}// 如果讀取到數字,放回緩沖區供下一次 cin >> i 讀取if (ch >= '0' && ch <= '9') {cin.putback(ch);//重新放回到輸入流中}cout << endl;}//if (cin.fail())
//{
//    // clear可以恢復流狀態位goodbitcin.clear();
//    // 我們還要把緩沖區中的多個字符都讀出來,讀到數字停下來,否則再去cin >> i還是會失敗//    char ch = cin.peek();
//    while (!(ch >= '0' && ch <= '9'))
//    {
//        ch = cin.get();
//        cout << ch;
//        ch = cin.peek();
//    }
//    cout << endl;
//}cout << cin.good() << endl;  // 1(true)cout << cin.eof() << endl;   // 0(false)cout << cin.bad() << endl;   // 0(false)cout << cin.fail() << endl;  // 0(false)cin >> i; // 現在可以正常讀取數字cout << i << endl;return 0;
}

輸出結果:

?

3、管理輸出緩沖區

?????????在輸出的時候,我們的結果不是直接輸出到控制臺的,而是先輸出到內存中的緩沖區。也就是說,操作系統可能會把多個輸出操作合并成一個輸出操作。不論是Windows系統還是Linux系統都是這樣,我們可以驗證一下:

#include <iostream>
#include<windows.h>
using namespace std;int main() {cout << "test1" << endl;cout << "test2" << endl;cout << "test3" << endl;cout << "test4" << endl;Sleep(5);//系統休眠五秒return 0;
}

? ? ? ? ?我們執行這串代碼,發現,在執行之后,控制臺窗口光標閃爍大約五秒,之后一次性輸出了所有的字符串。那么在這五秒中,這些字符串就在緩沖區中存放著。

? ? ? ? 那么為什么會這樣設計呢?因為設備的IO操作通常是很耗時的,允許操作系統將多個輸出操作組合為單一的設備寫操作會帶來很大的性能提升。

? ? ? ? ?每次觸發緩沖區刷新,我們緩沖區的內容就會輸出到控制臺或者文件中。那么什么情況下會觸發緩沖區刷新呢?第一,程序正常結束;第二緩沖區滿了;第三,當輸出操作符endl或者flush會立即刷新緩沖區;第四,我們使用了操作符unitbuf設置流的內部狀態沒來清空緩沖區,cerr設置了unitbuf,所以cerr輸出都是立即刷新的;第五,一個輸出流關聯到另一個流時,當這個流被讀寫時,輸出流會立即刷新緩沖區。

? ? ? ? 我們詳細說一下第五條。第五條是通過tie來實現的,比如,默認情況下cin和cout是綁定在一起的所以說當我們cin時,會刷新cout的緩沖區。我們也可以手動綁定cin和其他的東西。在競賽的時候,我們有時會關閉C++和C在每次輸入輸出后同步,解綁cin和cout關聯綁定的其他流。這些操作本質上都是為了提升效率。

ios_base::sync_with_stdio(false);//關閉C流與C++流同步
//解綁cin和cout關聯綁定的其他流
cin.tie(nullptr);
cout.tie(nullptr);

使用案例:?

#include<iostream>
#include<fstream>
using namespace std;
void func(ostream& os)
{os << "hello world";os << "hello C++";system("pause");//os << endl;//os << flush;//int i;//cin >> i;os << "hello cat";// "hello cat"是否輸出不確定system("pause");
}
int main()
{ofstream ofs("test.txt");//func(cout);// unitbuf設置后,ofs每次寫都直接刷新//ofs << unitbuf;// cin綁定到ofs,cin進?讀時,會刷新ofs的緩沖區// cin.tie(&ofs);func(ofs);return 0;
}

? ? ? ? ?大家可以測試一下以上代碼。

? ? ? ? 另外再說一下endl,endl其實是一個函數,endl相比\n的區別就是endl除了換行,還會強制刷新緩沖區。

4、標準IO流? ? ? ??

? ? ? ???這部分就比較熟悉了。C++標準IO流是默認關聯到控制臺窗口的。cin是istream類型全局對象,cout/cerr/clog是ostream類型的全局對象。內置類型都對這兩個類進行了重載,自定義類型粗腰自己重載<<和>>運算符。

? ? ? ? istream的cin對象支持轉換為bool值,進行條件邏輯判斷。如果讀取失敗(cin被標識eofbit或falibit)就會返回false。

int a = 0, b = 0;
while (cin >> a >> b)//如果讀取失敗會返回false,跳出循環
{cout << a << " " << b;
}

5、文件IO流

? ? ? ? ?文件IO流包含ofstream,ifstream,fstream,其中ofstream是輸出文件流,我們可以理解為,現在的輸出不是輸出到控制臺上了,而是輸出到文件中。ifstream是輸入文件流,可以從文件中讀入數據。fstream是ifstream和ofstream的派生類,即可以讀也可以寫。

? ? ? ? 文件IO流提供了非常豐富的文件打開方式,這些文件打開方式通過 | 可以組合起來,搭配出來更多種方式。搭配的方式是比C語言的文件操作更豐富的。

? ? ? ? 文件打開方式是通過 std::ios_base?標志位組合實現的,常用的標志位包括:

  • std::ios_base::in:以讀取方式打開文件。
  • std::ios_base::out:以寫入方式打開文件。
  • std::ios_base::app:以追加模式打開文件,寫入內容追加到文件末尾(總是在文件尾)。
  • std::ios_base::ate:打開文件后立即定位到文件末尾。
  • std::ios_base::trunc:如果文件已存在,清空文件內容。
  • std::ios_base::binary:以二進制模式打開文件。

? ? ? ? 這些值都是ios_base中定義的成員變量繼承下來的,并且他們也是組合的獨立二進制位值,需要組合時,可以或到一起。以下是他們可以搭配出的各種方式和C語言打開文件方式的對應。

?

? ? ? ? 對于圖片這種非文本文件,我們需要使用二進制打開方式,暴力的把所有的內容都讀取出來。

????????接下來我們通過代碼分別看幾個文件打開方式。?

#include<iostream>
#include<fstream>
using namespace std;
int main()
{ofstream ofs("test.txt");ofs.put('x');ofs.write("hello\nworld", 11);//一般使用\nofs << "2222";int x = 3333;ofs << x;ofs.close();ofs.open("test.txt", ios_base::out);//寫入文件(覆蓋)//或ofs.open("test.txt", ios_base::trunc);ofs.close();ofs.open("test.txt", ios_base::out | ios_base::app);//寫入文件(追加)ofs << "555" << endl;//需要注意,如果用out和ate其實會覆蓋ofs.open("test.txt", ios_base::in | ios_base::out);//讀寫文件(不覆蓋)ofs << "666" << endl;ofs.close();ofs.open("test.txt", ios_base::in | ios_base::out | ios_base::trunc);//讀寫文件(覆蓋)ofs << "777" << endl;ofs.close();std::fstream file("example.bin", std::ios::in | std::ios::out | std::ios::binary);//二進制模式打開文件return 0;
}

? ? ? ? 此外,我們用C++的文件操作實現圖片的復制操作。對于圖片來說,我們只能使用二進制,暴力的復制。注意在二進制讀寫時我們不能讀寫string。因為這時候我們讀的實際上是一個指向堆空間的指針,當string對象析構后,這塊空間就被釋放了。

#include<iostream>
#include<fstream>
using namespace std;
int main()
{// 實現?個圖??件的復制,需要??進制?式打開讀寫,第?個參數可以給?件的絕對路徑ifstream ifs("C:\\Users\\nobody\\Desktop\\test.png",ios_base::in | ios_base::binary);ofstream ofs("C:\\Users\\nobody\\Desktop\\test-copy.png",ios_base::out | ios_base::binary);int n = 0;while (ifs && ofs){char ch = ifs.get();ofs << ch;++n;}cout << n << endl;return 0;
}

? ? ? ? 需要注意,使用文件IO流時,ifstream和cin的規則類似,都提取到空格或者換行就終止。所以說我們要注意,如果文件中的文本是連成一片的,此時我們使用ifstream提取一個string類型的對象,實際上是把這一片內容去哪都提取走了。?

6、string IO流

? ? ? ? ostringstream是string的寫入流,ostringstream是ostream的派生類。istringstream是string的讀出流,istringstream是istream的派生類。stringstream是ostringstream和istringstream的派生類,即可以讀也可以寫。

? ? ? ? 我們來看一下案例了解一下:

#include <sstream>
#include <iostream>
#include <iomanip>
int main() {std::ostringstream oss;oss << "Hello, " << 42 << " world!";std::string result = oss.str();std::cout << result << std::endl;std::ostringstream oss1;oss1 << std::setprecision(3) << 3.14159;//設置精度,包含在頭文件iomanipstd::string result1 = oss1.str();std::cout << result1 << std::endl;return 0;
}

?????????istringstream:

#include <iostream>
#include <sstream>
#include <string>int main() {std::string data = "42 3.14 hello";std::istringstream iss(data);int num;double pi;std::string str;iss >> num >> pi >> str;std::cout << num << ", " << pi << ", " << str << std::endl;}

?????????stringstream:

????????stringstream系列底層維護了?個string類型的對象用來保存結果,使用方法跟上面的文件流類似,只是數據讀寫交互的都是底層的string對象。string流使用str函數獲取底層的string對象,或者寫入底層的string對象,具體細節參考下面代碼理解

#include <iostream>
#include <sstream>
#include <string>
#include<vector>int main() {std::stringstream ss;ss << "Hello, " << 123 << " world!";std::string result = ss.str();std::cout << result << std::endl; // 輸出:Hello, 123 world!std::string input = "apple orange banana";std::stringstream ss1(input);std::string token;std::vector<std::string> tokens;while (ss1 >> token) {tokens.push_back(token);}for (const auto& t : tokens) {std::cout << t << std::endl;}std::stringstream ss2;ss2 << "First use";std::cout << ss2.str() << std::endl;ss2.clear();ss2.str("");ss2 << "Second use";std::cout << ss2.str() << std::endl;return 0;
}

? ? ? ? 好了,今天的內容就分享到這,我們下期再見!

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/914713.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/914713.shtml
英文地址,請注明出處:http://en.pswp.cn/news/914713.shtml

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

相關文章

語音識別的速度革命:從 Whisper 到 Whisper-CTranslate2,我經歷了什么?

Whisper-CTranslate2&#xff1a;語音識別的速度革命 大家好&#xff0c;一個沉迷于 AI 語音技術的 “音頻獵人”。最近在處理大量播客轉錄項目時&#xff0c;我被傳統語音識別工具折磨得苦不堪言 ——RTX 3090 跑一個小時的音頻要整整 20 分鐘&#xff0c;服務器內存分分鐘爆滿…

JVM 內存模型詳解:GC 是如何拯救內存世界的?

JVM 內存模型詳解&#xff1a;GC 是如何拯救內存世界的&#xff1f; 引言 Java 虛擬機&#xff08;JVM&#xff09;是 Java 程序運行的基礎&#xff0c;其核心特性之一就是自動內存管理。與 C/C 不同&#xff0c;Java 開發者無需手動分配和釋放內存&#xff0c;而是由 JVM 自動…

分布式全局唯一ID生成:雪花算法 vs Redis Increment,怎么選?

在黑馬點評項目實戰中&#xff0c;關于全局唯一ID生成的實現方案選擇中&#xff0c;我看到有人提到了雪花算法&#xff0c;本文就來簡單了解一下雪花算法與Redis的incr方案的不同。在分布式系統開發中&#xff0c;“全局唯一ID”是繞不開的核心問題。無論是分庫分表的數據庫設計…

(新手友好)MySQL學習筆記(完):事務和鎖

事務和鎖事務transaction&#xff0c;一組原子性的SQL查詢&#xff0c;或者說是一個獨立的工作單元。如果能夠成功執行這組查詢的全部語句&#xff0c;就會執行這組查詢&#xff1b;如果其中任何一條語句無法成功執行&#xff0c;那么這組查詢的所有語句都不會執行。也就是說&a…

【CMake】使用 CMake 將單模塊 C 項目構建為庫并鏈接主程序

目錄1. 項目結構設計&#x1f4e6; 結構說明2. 項目文件內容2.1 頂層 CMakeLists.txt2.2 模塊 src/color/CMakeLists.txt ?【推薦寫法】?是否需要寫 project()&#xff1f;2.3 模塊頭文件 include/color.h2.4 模塊實現文件 src/color/color.c2.5 主程序 src/main.c3. 構建與運…

從零開始的云計算生活——番外4,使用 Keepalived 實現 MySQL 高可用

目錄 前言 一、架構原理? ?Keepalived 作用? ?MySQL 主從復制? 二、環境準備? 服務器要求?&#xff1a; 安裝基礎軟件? 三、配置 MySQL 主從復制 四、配置 Keepalived 主節點配置?&#xff08;/etc/keepalived/keepalived.conf&#xff09; 從節點配置 五、…

list類的常用接口實現及迭代器

目錄 1. list類的介紹 2.list類的常用接口 2.1 list類的常用構造 2.2 list類對象的容量操作 2.3 list迭代器 2.4 list類的常用操作 3.list的模擬實現 1. list類的介紹 list代表的是雙向鏈表&#xff0c;常見的有創建&#xff0c;增&#xff0c;刪&#xff0c;改幾個接口…

vscode Cline接入火山引擎的Deepseek R1

創建火山引擎Deepseek R1的API 在火山引擎管理控制臺中創建Deepseek R1推理接入點&#xff08;大模型&#xff09;&#xff0c;創建成功后會看到下圖效果。在操作中選擇API調用&#xff0c;在頁面中選擇OpenAI SDK&#xff0c;按照步驟找到baseUrl地址和API_KEY&#xff0c;后續…

新手向:自動化圖片格式轉換工具

大家好&#xff01;今天我要分享一個非常實用的Python小工具——圖片格式批量轉換器。如果你經常需要處理大量不同格式的圖片文件&#xff0c;或者需要統一圖片格式以便于管理&#xff0c;那么這個工具將會成為你的得力助手&#xff01;一、為什么需要圖片格式轉換&#xff1f;…

CUDA中的內存管理、鎖頁內存、UVA統一虛擬地址、零拷貝、統一內存

文章目錄0 前言1 swap內存跟鎖頁內存2 UVA(Unified Virtual Addressing)統一虛擬地址3 先看最普通的cuda內存分配、釋放、傳輸4 申請鎖頁內存4.1 cudaHostAllocDefault4.2 cudaHostAllocPortable4.3 cudaHostAllocWriteCombined4.3 cudaHostAllocMapped4.4 幾種鎖頁內存總結4.5…

微服務環境下的灰度發布與金絲雀發布實戰經驗分享

微服務環境下的灰度發布與金絲雀發布實戰經驗分享 在大規模微服務架構中&#xff0c;如何平滑安全地上線新功能是每個后端團隊的痛點。本文將結合生產環境中的真實案例&#xff0c;分享灰度發布&#xff08;Gray Release&#xff09;與金絲雀發布&#xff08;Canary Release&am…

MEF 在 WPF 中的簡單應用

MEF核心筆記MEF 的開發模式主要適用于插件化的業務場景中&#xff0c;C/S 和 B/S 中都有相應的使用場景&#xff0c;其中包括但不限于 ASP.NET MVC 、ASP WebForms、WPF、UWP 等開發框架。當然&#xff0c;DotNet Core 也是支持的。 以下是搜索到一些比較好的博文供參考&#…

Gitlab跑CICD的時候,maven鏡像和pom.xml使用的maven版本沖突導致沒辦法build成功的解決方法

是這樣的&#xff01;最近遇到一個非常棘手的難題&#xff0c;我搞了大概2周時間才把他弄出來&#xff0c;因為自己搭了個私服的maven倉庫&#xff0c;他不像maven官方倉庫一樣&#xff0c;可以跟nginx一樣轉的&#xff0c;所以遇到好幾個難點&#xff01;第一點&#xff1a;就…

Linux內核IPv4路由查找:LPC-Trie算法的深度實踐

在互聯網基礎設施的核心領域,路由查找性能直接決定了網絡轉發效率。Linux內核作為現代網絡系統的基石,其IPv4路由子系統采用了一種名為LPC-Trie(Level-Compressed Trie) 的創新數據結構,在net/ipv4/fib_trie.c文件中實現了高效的路由管理方案。本文將深入剖析這一機制的設…

【設計模式】裝飾(器)模式 透明裝飾模式與半透明裝飾模式

裝飾模式&#xff08;Decorator Pattern&#xff09;詳解一、裝飾模式簡介 裝飾模式&#xff08;Decorator Pattern&#xff09; 是一種 結構型設計模式&#xff0c;它允許你動態地給對象添加行為或職責&#xff0c;而無需修改其源代碼&#xff0c;也不需要使用繼承來擴展功能。…

NAT原理與實驗指南:網絡地址轉換技術解析與實踐

NAT實驗 NAT&#xff08;Network Address Translation&#xff0c;網絡地址轉換&#xff09;&#xff1a; NAT技術的介紹&#xff1a; 隨著Internet用戶的快速增長&#xff0c;以及地址分配不均等因素&#xff0c;IPv4地址&#xff08;約40億的空間地址&#xff09;已經陷入不…

設計模式之【觀察者模式】

目錄 觀察者模式中的角色 通過一個簡單案例來演示觀察者模式 被觀察者接口 事件類型 up主類作為被觀察者 觀察者接口 粉絲類作為觀察者 測試 測試結果 觀察者模式中的角色 被觀察者(observable)觀察者(observer) 通過一個簡單案例來演示觀察者模式 被觀察者接口 /*…

Linux sudo host權限提升漏洞(CVE-2025-32462)復現與原理分析

免責聲明 本文所述漏洞復現方法僅供安全研究及授權測試使用&#xff1b; 任何個人/組織須在合法合規前提下實施&#xff0c;嚴禁用于非法目的&#xff1b; 作者不對任何濫用行為及后果負責&#xff0c;如發現新漏洞請及時聯系廠商并遵循漏洞披露規則。 漏洞簡述 Linux sudo是l…

【uni-ui】hbuilderx的uniapp 配置 -小程序左滑出現刪除等功能

1.網址&#xff1a;https://ext.dcloud.net.cn/plugin?id181](https://ext.dcloud.net.cn/plugin?id181) 2.csdn講解&#xff1a;https://blog.csdn.net/qq_40323256/article/details/114337128 3.uni-ui git&#xff1a;https://github.com/dcloudio/uni-ui 4.官方網址文檔&…

記一次POST請求中URL中文參數亂碼問題的解決方案

POST請求中URL中文參數亂碼前言&#xff1a;一個常見的開發痛點一、問題現象與原因深度解析1. 典型問題場景2. 根本原因分析URL編碼規范問題&#xff1a;編碼解碼過程不一致&#xff1a;IE瀏覽器特殊行為&#xff1a;二、前端解決方案1. 手動編碼URL參數&#xff08;推薦&#…