c++中的輸入輸出流(標準IO,文件IO,字符串IO)

目錄

(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;   // 輸入數據到緩沖區,然后從緩沖區讀取數據給myIntcin >> myLong;  // 緩沖區如果還有數據,直接讀取數據給myLongcin >> mybuf;   // 緩沖區如果還有數據,直接讀取數據給mybufcout << "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);  // 然后將緩沖區的剩余數據提取到buf2cout << "buf1:" << buf1 << endl;  // buf1:aacout << "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:bcin.getline(buf2, 256);  // 然后將緩沖區的剩余數據提取到buf2cout << "buf1:" << buf1 << endl;  // buf1:aacout << "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 >> ncin.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();// 輸出:helreturn 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.普通的coutcout << "hello world" << endl;// 2.使用類成員函數:對下一次的cout進行格式化輸出cout.width(10);   // 設置輸出的寬度是30cout.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;  // 普通輸出效果:0x7bcout << 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;        //以十六進制形式輸出整數acout << "oct:" << setbase(8) << a << endl; //以八進制形式輸出整數achar 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:173China
*****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 timereturn 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; // 865string strValue1;strValue1 = s.str();cout << strValue1 << endl; // 865s.str(""); // 將stringstream底層管理的string對象設置為""// 否則多次轉化時,會將結果全部累積在底層string對象中s.clear(); // 清空s, 不清空會轉化失敗double d = 12.34;s << d;s >> sa;cout << sa << endl; // 12.34string strValue2;strValue2 = s.str();cout << strValue2 << endl; // 12.34return 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;               // 構造方式1ostr1 << "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.pswp.cn/bicheng/84170.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/84170.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/84170.shtml

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

相關文章

人工智能學習06-循環

人工智能學習概述—快手視頻 人工智能學習06-循環—快手視頻

【電路】阻抗匹配

&#x1f4dd; 阻抗匹配 一、什么是阻抗匹配&#xff1f; 阻抗匹配&#xff08;Impedance Matching&#xff09;是指在電子系統中&#xff0c;為了實現最大功率傳輸或最小信號反射&#xff0c;使信號源、傳輸線與負載之間的阻抗達到一種“匹配”狀態的技術。 研究對象&#x…

【vue】Uniapp 打包Android 文件選擇上傳問題詳解~

需求 uniapp兼容android app&#xff0c;pc&#xff0c;h5的文件選擇并上傳功能。 需要支持拍照和相冊選擇&#xff0c;以及選擇其他類型文件上傳~ 實踐過程和問題 開始使用uni-file-picker組件 以為很順利&#xff0c;android模擬器測試…… 忽略了平臺兼容性提示~&#…

Python:操作 Excel 格式化

??Python 操作 Excel 格式化完整指南(openpyxl 與 xlsxwriter 雙方案) 在數據處理和報表自動化中,Python 是一把利器,尤其是配合 Excel 文件的讀寫與格式化處理。本篇將詳細介紹兩大主流庫: openpyxl:適合讀取與修改現有 Excel 文件xlsxwriter:適合創建新文件并進行復…

Prompt Enginering(提示工程)先進技術

前沿 CoT&#xff08;Chain-of-Thought&#xff09;和 ReACT&#xff08;Reasoning and Acting&#xff09;是兩種先進的 Prompt Engineering&#xff08;提示工程&#xff09; 技術&#xff0c;旨在提升大語言模型&#xff08;LLM&#xff09;的推理、規劃和執行能力。 CoT&a…

【C++系列】模板類型特例化

1. C模板類型特例化介紹 ??定義??&#xff1a;模板類型特例化&#xff08;Template Specialization&#xff09;是C中為模板的特定類型提供定制實現的機制&#xff0c;允許開發者對通用模板無法處理的特殊類型進行優化或特殊處理。 ??產生標準??&#xff1a; C98/03…

AI數據分析在體育中的應用:技術與實踐

在現代體育競技領域&#xff0c;"數據驅動"已不再是一個遙遠的概念。尤其隨著人工智能&#xff08;AI&#xff09;和大數據分析的不斷成熟&#xff0c;從職業俱樂部到賽事直播平臺&#xff0c;從運動員訓練到球迷觀賽體驗&#xff0c;AI正以前所未有的方式滲透并改變…

計數思想-眾數

11203-眾數 題目描述(Description) 眾數是指在一組數據中&#xff0c;出現次數最多的數。例如&#xff1a;1, 1, 3 中出現次數最多的數為 1&#xff0c;則眾數為 1。 給定一組數&#xff0c;你能求出眾數嗎&#xff1f; 輸入格式(Format Input) 第 1 行輸入一個整數 n (1 &…

【Go語言基礎【20】】Go的包與工程

文章目錄 零、概述一、包基礎1、包的核心作用2、包的聲明與結構2.1、 包聲明&#xff08;Package Declaration&#xff09;2.2、 包的目錄結構&#xff08;工程視角&#xff09; 3、包的導入與調用3.1、導入包&#xff08;Import Packages&#xff09;3.2、 調用包成員3.3、 導…

《C++初階之入門基礎》【命名空間 + 輸入輸出 + 缺省參數 + 函數重載】

【命名空間 輸入&輸出 缺省參數 函數重載】目錄 前言&#xff1a;---------------hello world---------------比較C語言和C的第一個程序&#xff1a;hello word ---------------命名空間---------------什么是命名空間&#xff1f;怎么使用命名空間&#xff1f;怎么定義…

java綜合項目開發一課一得

文章目錄 Java 綜合項目課程學習&#xff1a;探索與成長之路一、課程初體驗&#xff1a;從理論走向實踐&#xff08;一&#xff09;系統學習 Java 核心理論知識&#xff08;二&#xff09;開啟首個實踐項目 —— 圖書管理系統 二、項目攻堅&#xff1a;挑戰與突破&#xff08;一…

JuiceFS v1.3-Beta2:集成 Apache Ranger,實現更精細化的權限控制

在大數據場景中&#xff0c;文件系統和應用組件的權限管理至關重要。在最新發布的 JuiceFS 社區版 v1.3-Beta 2 中&#xff0c;JuiceFS 引入了與 Apache Ranger 的集成&#xff0c;提供了更為靈活和細粒度的權限控制解決方案。 本文將介紹 JuiceFS 社區版如何與 Apache Ranger…

6月8日day48打卡

隨機函數與廣播機制 知識點回顧&#xff1a; 隨機張量的生成&#xff1a;torch.randn函數卷積和池化的計算公式&#xff08;可以不掌握&#xff0c;會自動計算的&#xff09;pytorch的廣播機制&#xff1a;加法和乘法的廣播機制 ps&#xff1a;numpy運算也有類似的廣播機制&…

計算機常用快捷鍵分類匯總,涵蓋 Windows、macOS 以及通用軟件場景

一、系統通用快捷鍵 功能Windows 快捷鍵macOS 快捷鍵復制Ctrl CCommand C粘貼Ctrl VCommand V剪切Ctrl XCommand X撤銷Ctrl ZCommand Z全選Ctrl ACommand A保存Ctrl SCommand S打印Ctrl PCommand P新建窗口/標簽頁Ctrl NCommand N關閉當前窗口/標簽頁Ctrl WC…

ES6中的Map與Set數據結構的簡單應用

一、Map定義和基本用法 Map是一種鍵值對集合&#xff0c;其中鍵和值都可以是任何類型&#xff08;對象、原始值等&#xff09;。與普通對象不同&#xff0c;Map保持鍵值對的插入順序&#xff0c;并且允許使用任何類型的鍵。 1、創建Map const map new Map()2、添加鍵值對。…

25.【.NET8 實戰--孢子記賬--從單體到微服務--轉向微服務】--單體轉微服務--用戶服務接口

用戶管理是任何系統的基礎功能之一&#xff0c;本篇介紹了如何實現一個完整的用戶管理模塊&#xff0c;包括用戶信息的增刪改查、用戶狀態管理、分頁查詢、數據驗證和權限控制。核心代碼實現部分涵蓋了控制器&#xff08;UserController&#xff09;、服務接口&#xff08;IUse…

基于深度學習的無人機軌跡預測

完整代碼見文末 隨著無人機技術的不斷發展,無人機在農業、物流、監控等領域的應用日益廣泛。精準的軌跡預測不僅能夠提高無人機飛行的效率和安全性,還能在應對復雜環境下的突發狀況時做出迅速反應。因此,基于深度學習的無人機軌跡預測已成為當前研究和應用的熱門方向。 無…

AUTOSAR實戰教程--DoIP_02_診斷鏈路建立流程

第一步&#xff1a;DoIP實體車輛聲明/診斷儀車輛識別請求 打開激活線以后&#xff0c;DoIP實體發的三幀車輛聲明報文。其中包含了DoIP實體的診斷邏輯地址&#xff08;可以類比DoCAN的物理請求/響應地址&#xff09;&#xff0c;對應車輛的VIN碼&#xff08;若已配置&#xff0…

跟我學c++中級篇——多線程中的文件處理

一、文件處理 作為IO處理的一種重要場景&#xff0c;文件處理是幾乎所有編程都無法繞過的一個情況。稍微復雜的一些的程序都可能需要文件處理&#xff0c;不管這種文件處理對開發者來說是顯式的還是隱式的。相對于其它語言&#xff0c;C并未提供多么好的文件處理API接口&#…

Flutter知識點匯總

Flutter架構解析 1. Flutter 是什么?它與其他移動開發框架有什么不同? Flutter 是 Google 開發的開源移動應用開發框架,可用于快速構建高性能、高保真的移動應用(iOS 和 Android),也支持 Web、桌面和嵌入式設備。。它與其他移動開發框架(如 React Native、Xamarin、原…