1. 流
- 流:數據從一個對象到另一個對象的傳輸。
- 功能:標準輸入輸出+文件處理
分類 | 含義 |
---|---|
文本流 | 一串ASCII字符 |
二進制流 | 一串二進制 |
2. 流類型
標準庫定義了三大類流類型:標準I/O流、文件流、字符串流
- 標準I/O流
-
ios
是抽象類 -
ostream
是cout
、clog
、cerr
的類 -
istream
是cin
的類
-
- 文件流類型
-
ifstream
從文件讀取數據 -
ofstream
向文件寫入數據 -
iofstream
文件讀寫數據
-
- 字符串流類型
-
istringstream
從string
讀取數據 -
ostringstream
向string
寫入數據 -
iostringstream
讀寫string
數據
-
3. 流對象
通常標準I/O流對象是全局對象不需要定義,而文件流對象和字符串流對象需要用戶定義。
標準I/O流對象有以下四個:
No. | 全局流對象 | 名稱 | 緩存 |
---|---|---|---|
1 | cout |
標準輸出流 | 帶緩存 |
2 | cin |
標準輸入流 | 帶緩存 |
3 | clog |
標準日志流 | 帶緩存 |
4 | cerr |
標準錯誤流 | 無緩存 |
注意:流對象通常都不能復制。
4. 流對象狀態
流對象狀態在某一個時刻必定處于以下四個狀態之一。
No. | 狀態 | 含義 |
---|---|---|
1 | good() |
前一個流操作成功 |
2 | eof() |
到輸入尾/文件尾 |
3 | fail() |
發生意外事情(讀取失敗) |
4 | bad() |
發生意外嚴重事情(磁盤讀取失敗) |
5. I/O操作
I/O操作主要有如下五種:
- 輸入操作:
in >> x
或者getline(in,s)
- 輸出操作:
out << x
- 操作符
- 流狀態
- 格式化
- 輸出流默認設置
類型 | 進制 | 寬度 | 對齊 | 填充 | 精度 |
---|---|---|---|---|---|
整數 | 十進制 | 0 | 右對齊 | 空格 | 1 |
實數 | 十進制 | 0 | 右對齊 | 空格 | 6位數 |
字符串 | - | 0 | 右對齊 | 空格 | 字符串實際長度 |
- 格式控制
- 格式控制成員函數
流對象.格式控制函數(實參)
- 預定義格式控制函數
預定義格式控制函數(實參)
- 流的輸出控制格式
作用 | 格式控制成員函數 | 預定義格式控制函數 | 預定義格式控制符/操作子 | 效果持續 |
---|---|---|---|---|
進制 |
flags() setf() unsetf()
|
setiosflags() |
dec oct hex showbase
|
能持續 |
寬度 | width(n) |
setw(n) |
- | 不能持續 |
對齊 |
flags() setf() unsetf()
|
setiosflags() |
right left internal
|
能持續 |
填充 | fill(c) |
setfill(c) |
- | 能持續 |
精度 | precision(n) |
setprecision(n) |
- | 能持續 |
- 流的輸出控制格式:
dec
oct
hex
- 數據輸入成員函數
字符輸入成員函數:get()
字符串輸入成員函數:getline()
- 數據輸出成員函數:
put()
1. 對齊方式
flag | manipulator | 作用 |
---|---|---|
ios::left |
left |
居左 |
ios::right |
right |
居右 |
ios::internal |
internal |
輸出符號或進制后填充 |
- 成員函數方式
#include <iostream>
using namespace std;
int main(){
int n = -11;
cout.width(6);
cout.flags(ios::right);
cout << n << endl;
cout.width(6);
cout.flags(ios::left);
cout << n << endl;
cout.width(6);
cout.flags(ios::internal);
cout << n << endl;
}
- 操作子方式
#include <iostream>
#include <iomanip>
using namespace std;
int main(){
int n = -11;
cout << setw(6) << right << n << endl;
cout << setw(6) << left << n << endl;
cout << setw(6) << internal << n << endl;
}
- 混合方式
#include <iostream>
using namespace std;
int main(){
int n = -11;
cout.width(6); cout << left << n << endl;
cout.width(6); cout << right << n << endl;
cout.width(6); cout << internal << n << endl;
}
2. 整數輸出格式
flag | manipulator | 作用 | 是否默認 |
---|---|---|---|
ios::dec |
dec |
十進制 | 是 |
ios::oct |
oct |
八進制 | 否 |
ios::hex |
hex |
十六進制 | 否 |
ios::uppercase |
uppercase |
使用大寫輸出十六進制 | 否 |
ios::showbase |
showbase |
輸出帶有進制的字符 | 否 |
- 成員函數方式
#include <iostream>
using namespace std;
int main(){
int n = 11;
cout.flags(ios::dec);
cout << n << endl;
cout.flags(ios::hex);
cout << n << endl;
cout.flags(ios::oct);
cout << n << endl;
cout.flags(ios::showbase|ios::dec);
cout << n << endl;
cout.flags(ios::showbase|ios::oct);
cout << n << endl;
cout.flags(ios::showbase|ios::hex);
cout << n << endl;
cout.flags(ios::showbase|ios::uppercase|ios::dec);
cout << n << endl;
cout.flags(ios::showbase|ios::uppercase|ios::oct);
cout << n << endl;
cout.flags(ios::showbase|ios::uppercase|ios::hex);
cout << n << endl;
}
- 操作子方式
#include <iostream>
using namespace std;
int main(){
int n = 11;
cout << dec << n << endl;
cout << hex << n << endl;
cout << oct << n << endl;
cout << showbase << dec << n << endl;
cout << oct << n << endl;
cout << hex << n << endl;
cout << uppercase << dec << n << endl;
cout << oct << n << endl;
cout << hex << n << endl;
}
3. 浮點數輸出格式
flag | 作用 | 是否默認 | 精度 |
---|---|---|---|
ios::defaultfloat |
默認浮點數格式 | 是 | 最多保留多少位數字 |
ios::scientific |
科學計數法輸出浮點數 | 否 | 小數點后最多保留多少位數字 |
ios::fixed |
定點數方式輸出實數 | 否 | 小數點后最多保留多少位數字 |
如果浮點數沒有小數時默認不顯示小時點,使用
ios::showpoint
可以強制輸出浮點數時,必須帶小數點。
定點數方式比浮點數方式更精確
取浮點數精確度時,設置ios::fixed
- 成員函數方式
#include <iostream> // cout, std::fixed, std::scientific
using namespace std;
int main () {
double a = 3.1415926534;
double b = 2006.0;
double c = 1.0e-10;
cout.precision(5);
cout << "default:\n";
cout << a << endl << b << endl << c << endl;
cout << "fixed:\n";
cout.flags(ios::fixed);
cout << a << endl << b << endl << c << endl;
cout << "scientific:\n";
cout.flags(ios::scientific);
cout << a << endl << b << endl << c << endl;
return 0;
}
- 操作子方式
#include <iostream> // std::cout, std::fixed, std::scientific
#include <iomanip>
using namespace std;
int main () {
double a = 3.1415926534;
double b = 2006.0;
double c = 1.0e-10;
cout << setprecision(5)
<< "default:\n"
<< a << endl << b << endl << c << endl;
cout << "fixed:\n" << fixed
<< a << endl << b << endl << c << endl;
cout << "scientific:\n" << scientific
<< a << endl << b << endl << c << endl;
return 0;
}
- 混合方式
#include <iostream> // std::cout, std::fixed, std::scientific
int main () {
double a = 3.1415926534;
double b = 2006.0;
double c = 1.0e-10;
std::cout.precision(5);
std::cout << "default:\n";
std::cout << a << '\n' << b << '\n' << c << '\n\n'
std::cout << "fixed:\n" << std::fixed;
std::cout << a << '\n' << b << '\n' << c << '\n\n'
std::cout << "scientific:\n" << std::scientific;
std::cout << a << '\n' << b << '\n' << c << '\n\n';
return 0;
}
4.布爾類型輸出格式
flag | manipulator | 作用 | |
---|---|---|---|
ios::boolalpha |
boolalpha |
把bool 值以字符串true /false 輸出 |
否 |
5. 其它
flag | manipulator | 作用 | 默認 |
---|---|---|---|
ios::showpos |
showpos |
輸出十進制0或者正數時,帶+號 | 否 |
- 成員函數方式
#include <iostream> // std::cout, std::showpos, std::noshowpos
using namespace std;
int main () {
int p = 1;
int z = 0;
int n = -1;
cout.setf(ios::showpos); cout << p << '\t' << z << '\t' << n << endl;
cout.unsetf(ios::showpos); cout << p << '\t' << z << '\t' << n << endl;
return 0;
}
- 操作子方式
#include <iostream> // std::cout, std::showpos, std::noshowpos
using namespace std;
int main () {
int p = 1;
int z = 0;
int n = -1;
cout << showpos << p << '\t' << z << '\t' << n << endl;
cout << noshowpos << p << '\t' << z << '\t' << n << endl;
return 0;
}
復數虛部
a+bi
使用showpos
非常合適。
問題
- 浮點數八進制/十六進制輸出結果?
- 下列代碼為什么能轉化成十六進制?
#include <iostream>
#include <iomanip> // setiosflags() , ios::hex
using namespace std;
int main(){
cout << setiosflags(ios::hex) << 10 << endl;
}
最新版C++的iostream
庫中,在使用setiosflags()
前要先使用resetiosflags()
清除舊有相應信息。
cout << resetiosflags(ios::basefield)<< setiosflags(ios::hex) << 10 << endl;
以下三類格式化在使用setiosflags()
,要先使用resetiosflags()
清除舊有相應信息。
stringstream
- 字符串轉化數字
istringstream iss(str);
int n;
iss >> n;
C++11提供如下函數簡化字符串轉數字
stoi()
stol()
stoul()
stoll()
stoull()
stof()
stod()
stold()
數字轉化字符串
int n;
ostringstream oss;
oss << n;
oss.str();
練習
- 8. 字符串轉換整數 (atoi)
- 實現空格分割字符串
vector<string> split(const string& str){
vector<string> res;
istringstream iss(str);
string s;
while(iss >> s){
res.push_back(s);
}
return res;
}
C++文件讀寫
文件:文件名+文件內容(有序數據集合)
文件名:字符序列
文件數據格式:二進制文件/文本文件C++文件操作流程
- 打開文件
- 讀寫文件
- 關閉文件
- 打開/關閉文件
操作 | 代碼 |
---|---|
定義讀文件流對象 | ifstream 讀文件流對象 |
定義寫文件流對象 | ofstream 寫讀文件流對象 |
定義讀寫文件流對象 | fstream 讀寫讀文件流對象 |
成員函數打開文件 | 文件流對象.open(文件名,文件打開方式) |
構造函數打開文件 | 文件流類 對象(文件名,文件打開方式) |
判斷文件是否打開 | !文件流對象 |
關閉文件 | 文件流對象.close(變量) |
- 文本文件讀寫
操作 | 代碼 |
---|---|
提取運算符讀文件 | 文件流對象 >> 變量 |
插入運算符寫文件 | 文件流對象 << 變量 |
成員函數讀文件 | 文件流對象.get(變量) |
成員函數寫文件 | 文件流對象.put(變量) |
- 二進制文件讀寫
操作 | 代碼 |
---|---|
讀函數 | read() |
寫函數 | write() |
測試文件結束 | eof() |
- 文件打開方式
類型 | 代碼 |
---|---|
讀 | ios::in |
寫 | ios::out |
添加末尾 | ios::app |
已存在文件 | ios::nocreate |
未打開文件 | ios::noreplace |
二進制 | ios::binary |
- 文件對象指針位置函數
操作 | 代碼 |
---|---|
獲取讀位置 | 對象.tellg() |
獲取寫位置 | 對象.tellp() |
設置讀位置 | 對象.seekg() |
設置寫位置 | 對象.seekp() |
- 函數后綴
p
表示put
(輸出),后綴g
表示get
(輸入)。- 如果文件是以
ios::app
文本追加方式打開,指針位置默認在文件結束,其他情況默認在文件開頭。
- 文件對象狀態函數
操作 | 代碼 |
---|---|
判斷文件對象狀態是否正常 | 對象.good() |
重置文件對象狀態 | 對象.clear() |
流式文件類型
-
stream
流文件 - 文件指針
FILE*
stream
流文件讀寫
-
ifstream
文件讀
ifstream fin(文件路徑);
fin >> 變量
fin.close();
-
ofstream
文件寫
ofstream fout(文件路徑);
fout << 變量
fout.close();
-
fstream
文件寫
fstream fs(文件路徑,ios::in|ios::out|ios::app);
if(fs){
fs << 變量;
fs.seekg(ios::beg);
fs >> 變量;
fs.close();
}
fstream
的打開模式是否創建不存在的文件
No. | 打開模式 | 是否創建不存在的文件 |
---|---|---|
1 | ios::in |
否 |
2 | ios::out |
是 |
3 | ios::in|ios::out |
否 |
4 | ios::in|ios::out|ios::app |
是 |
先讀后寫
fstream fs("test.txt",ios::in|ios::out|ios::app);
if(fs){
// 讀文件
string str;
while(fs >> str){
cout << str << endl;
}
fs.clear();// 清除錯誤
// 寫文件
while(cin >> str){
fs << str << endl;
}
}
先寫后讀
fstream fs("test.txt",ios::in|ios::out|ios::app);
if(fs){
// 寫文件
string str;
while(cin >> str)
fs << str << endl;
// 讀文件
fs.seekg(ios::beg);
while(fs >> str)
cout << str << endl;
// 后續如果對fs操作,需要清空fs狀態
}else{
cerr << "file not exist " << endl;
}
文件指針FILE
讀寫
-
FILE
文件指針讀
FILE* fp = fopen(文件路徑,"r");
fscanf(,fp);
fclose(fp);
-
FILE
文件指針寫
FILE* fp = fopen(文件路徑,"w");
fprintf(,fp);
fclose(fp);
對象的序列化與反序列化
序列化:把對象轉化成文本/二進制
反序列化:把文本/二進制轉化成對象
文件重定向
freopen(文件路徑,操作,標準IO)
操作:讀(r
) 寫(w
)
- 重定向寫
freopen("out.txt","w",stdout);
cout << "out data" <<endl;
- 重定向讀
freopen("in.txt","r",stdin);
string str;
cin >> str;
幾種常見的文件讀取方式對比
-
ifstream
+fin
-
freopen
+cin
+sync_with_stdio(false)
-
FILE*
+fscanf
-
freopen
+scanf
-
freopen
+cin
實現日志模塊
freopen("test.log","w",stderr);
cerr << "FATAL";
cerr << "ERROR";
clog << "WARNING";
clog << "INFO";
clog << "DEBUG";
擴展閱讀
- <<C++程序設計語言(第4部分:標準庫) 中文第四版>>:第38章 I/O流