目錄
- 1、輸入輸出類介紹
- 1.C/C++文件操作對比
- 2.什么是流?
- 3.C++ I/O流類層次
- 4.帶緩沖的輸入輸出
- 5.gcc編譯器cin.in_avail()
- 2、向文件寫入數據
- 1.寫文件小練習
- 2.如何將信息同時輸出到文件和屏幕?
- 3、從文件讀數據
- 1.檢測文件是否成功打開
- 2.檢測是否已到文件末尾
- 3.讀取文件小練習
- 4.bad()函數能否用來判斷文件流是否成功打開?
1、輸入輸出類介紹
1.C/C++文件操作對比
2.什么是流?
流是一個數據序列。
一個流是有兩個端點的,一邊是data source(數據源),一邊是程序。
一個I / O流表示輸入源或輸出目的地。流可以表示許多不同種類的源和目標,包括磁盤文件,設備,其他程序和內存陣列。
流支持許多不同類型的數據,包括簡單字節,原始數據類型,本地化字符和對象。一些流只是傳遞數據;其他則以有用的方式操縱和轉換數據。
無論它們在內部如何工作,所有流都向使用它們的程序提供相同的簡單模型:流是數據序列。
程序使用輸入流從源中一次讀取一項數據:
程序使用輸出流將數據寫入目的地,一次寫入一項:
摘自:I / O流
3.C++ I/O流類層次
C++的流類主要有五類:
流基類(ios_base和ios)
標準輸入輸出流類(istream/ostream/iostream)
字符串流類(istringstream/ostringstream)
文件流類(ifstream/ofstream/fstream)
緩沖區類(streambuf/stringbuf/filebuf)
標準輸入輸出流對象 cin 和 cout 分別是類 istream 和 ostream 的實例
字符串流:將各種不同的數據格式化輸出到一個字符串中,可以使用I/O操縱器控制格式;反之也可以從字符串中讀入各種不同的數據。
4.帶緩沖的輸入輸出
C++的I/O流是有內部緩沖區的。
c = cin.get(void)每次讀取一個字符并把由Enter鍵生成的換行符留在輸入隊列中
#include<iostream>using namespace std;int main() {char c;int i = 0;do {c = cin.get();cout << ++i << " : " <<static_cast<int>(c) << endl;} while (c != 'q');return 0;}
本部分要展示的內容如下:
1、鍵盤輸入一個字母后回車,實際進入緩沖區的是兩個字符
2、使用cin輸入信息后,有換行字符殘留在緩沖區,從而導致return語句前的cin.get()不起作用
#include <iostream>int main()
{//拿到cin對象的緩沖區指針auto p = std::cin.rdbuf();//從鍵盤讀入字符到緩沖區,保留所有字符在緩沖區auto x = std::cin.peek();std::cout << "x= " << x << std::endl;//顯示緩沖區中的字符數量//由于每次讀取返回值都不一樣,所以先將初始值保存auto count = p->in_avail();std::cout << "There are " << count << "characters in the buffer." << std::endl;//把緩沖區的字符都取出來并顯示for (int i = 0; i < count; i++){std::cout << i + 1 << ":" << std::cin.get() << std::endl;}std::cin.get();return 0;
}
5.gcc編譯器cin.in_avail()
在使用gcc編譯器的時候,存在這樣一種意外的情況:
無論輸入多少個字符, cin.in_avail()函數返回值永遠是0。
這是由于GCC編譯器中配套的libstdc++實現中的問題(可以看作是標準庫gcc實現的一個bug,或者一個特性)。
解決辦法是,在使用cin之前,插入下面一行代碼
cin.sync_with_stdio(false);
簡單解釋原因:GCC的libstdc++默認是保證C++的cin與C的stdin同步的。
2、向文件寫入數據
ofstrem可向文本文件中寫數據.
輸出數據的流程:
文件已存在,則直接清除內容。
Writing Data to a File – Auto type recognition (自動類型識別)
1.寫文件小練習
本部分要展示的內容如下:
1、創建文件輸出流
2、向文件寫數據
output << “Lilei” << " " << 90.5 << endl;
output << “HanMeimei” << " " << 85 << endl;
3、關閉文件
4、用文本編輯器打開文件,對比代碼語句檢查結果
//std::c++latest
#include <fstream>
#include <iostream>
#include <filesystem>using std::ifstream;
using std::ofstream;
using std::cout;
using std::endl;
namespace fs = std::filesystem;int main()
{//第一步,關聯文件fs::path p{ "scores.txt" };//第二步,創建一個流輸出對象ofstream output{ p };double lileiScore{ 90.5 };int hanmeimeiScore{ 84 };output << "Lilei " << lileiScore << endl;output << "HanMeimei " << hanmeimeiScore << endl;output.close();cout << "size of " << p << " is " << fs::file_size(p) << endl;std::cin.get();return 0;
}
打開一個輸出文件流的方法包括:
2.如何將信息同時輸出到文件和屏幕?
在軟件的調試技術中,很重要的一個技術是將軟件運行過程中的一些信息寫入到“日志文件”中。但是同時還要將信息顯示到屏幕上,以方便程序員實時查看這些信息。
最簡單的一種辦法是這樣的:
std::ofstream output("debug.log", ios::out);
output << __FILE__ << ":" << __LINE__ << "\t" << "Variable x = " << x;
cout << __FILE__ << ":" << __LINE__ << "\t" << "Variable x = " << x;
下面使用streambuf構造一個自己的類,來實現這個功能
#include <streambuf>
#include <iostream>
#include <fstream>//Linux tee命令用于讀取標準輸入的數據,并將其內容輸出成文件。
//tee指令會從標準輸入設備讀取數據,將其內容輸出到標準輸出設備,同時保存成文件。
class teebuf : public std::streambuf
{
public:// Construct a streambuf which tees output to both input// streambufs.teebuf(std::streambuf* sb1, std::streambuf* sb2): sb1(sb1), sb2(sb2){}
private:// This tee buffer has no buffer. So every character "overflows"// and can be put directly into the teed buffers.virtual int overflow(int c){if (c == EOF){return !EOF;}else{int const r1 = sb1->sputc(c);int const r2 = sb2->sputc(c);return r1 == EOF || r2 == EOF ? EOF : c;}}// Sync both teed buffers.virtual int sync(){int const r1 = sb1->pubsync();int const r2 = sb2->pubsync();return r1 == 0 && r2 == 0 ? 0 : -1;}
private:std::streambuf* sb1;std::streambuf* sb2;
};class teestream : public std::ostream
{
public:// Construct an ostream which tees output to the supplied// ostreams.teestream(std::ostream& o1, std::ostream& o2);
private:teebuf tbuf;
};teestream::teestream(std::ostream& o1, std::ostream& o2): std::ostream(&tbuf), tbuf(o1.rdbuf(), o2.rdbuf())
{
}int main()
{std::ofstream output("debug.log");//1、創建文件/屏幕輸出流對象teeteestream tee(std::cout, output);auto x = 1.1;tee << __FILE__ << ":" << __LINE__ << "\t" << "Variable x = " << x;return 0;
}
效果:
3、從文件讀數據
ifstrem可從文本文件中讀數據,并檢測文件是否成功打開。
了解數據格式
若想正確讀出數據,必須確切了解數據的存儲格式。
用流提取運算符從文件流中讀數據,所讀入的信息的長度與流提取運算符右側的變量的類型有關。
1.檢測文件是否成功打開
可能出現錯誤:
1、讀文件時文件不存在
2、寫文件時介質只讀
檢測文件是否正確打開的方法:
1、open()之后馬上調用fail()函數
2、fail()返回true, 文件未打開
ofstream output("scores.txt");
if (output.fail()) {cout << R"(Can't open file "scores.txt"!)";}
2.檢測是否已到文件末尾
若你不知道文件有多少行,還想把他們全讀出來,用eof()函數檢查是否是文件末尾
由于get函數返回值是int,所以需要強制類型轉換再進行屏幕輸出。
ifstream in("scores.txt");
while (in.eof() == false) {cout << static_cast<char>(in.get());
}
3.讀取文件小練習
本部分要展示的內容如下:
1、創建文件輸入流,打開文件score.txt
2、用>>從文件讀取數據
3、使用fail()函數檢測文件是否打開
4、將讀文件語句放入循環中,使用eof()作為循環條件
5、關閉文件
//std::c++latest
#include <fstream>
#include <iostream>
#include <filesystem>
#include <string>
using std::ifstream;
using std::ofstream;
using std::cout;
using std::endl;
using std::string;
namespace fs = std::filesystem;int main()
{//第一步,關聯文件fs::path p{ "scores.txt" };//第二步,創建一個流輸入對象ifstream input{ p };//第三步使用fail判斷流是否正常打開if (input.fail()){cout << "Can't open file " << p << endl;std::cin.get();return 0;}//第四步,定義一些變量去存這些數據string name{ "" };double score{ 0.0 };//讀取文件中的姓名和分數//input >> name >> score;//cout << name << " " << score << endl;//input >> name >> score;//cout << name << " " << score << endl;while (input.eof() == false){cout << static_cast<char>(input.get());}std::cin.get();return 0;
}
4.bad()函數能否用來判斷文件流是否成功打開?
在ifstream和ofstream類中,除了fail()函數之外,還有bad()函數。
那么我們能否用bad()函數取代fail()函數判斷流是否成功打開?
不能,bad() 如果出現意外的問題,如文件受損或硬件故障,最后一次讀取數據的時候發生了這樣的問題,方法bad()將返回true.