C++之路 Day5

什麼是IO?我們在學習計算的組成時知道:計算機由輸入、輸出設備,顯示器,存儲器,處理器組成。在程序中要理解什麼是IO,我們需要先明白一個概念:“流”。

      流?看到這個字,我們能想到的事物有人流,水流,車流等。這些事物都有一些特點,比如有方向性,一定數量級。在計算機中流是個抽象的概念,是對輸入輸出設備的抽象,這些設備可以是文件、網絡、內存等。流具有方向性。流可分爲字節流和字符流。

      數據流?

            程序數據 之間的交互是以流的形式進行。打開文件可以理解爲打開數據流,關閉文件可以理解爲關閉數據流。

緩衝區?

      是內存中的一塊區域。

      爲什麼需要緩衝區?

            因爲內存操作比設備操作快,爲了提高讀寫效率,需要等設備處理完後的數據累計到內存緩衝區一定數量後再交給CPU統一處理。

C ++ I / O發生在流中,這是字節序列。如果字節從鍵盤,磁盤驅動器或網絡連接等設備流向主存儲器,則稱爲輸入操作,如果字節從主存儲器流向顯示屏,打印機,磁盤驅動器等設備或者網絡連接等,這稱爲輸出操作。

Basic Input/Output:

      這裏的輸出一般是理解輸出到屏幕,輸入來自鍵盤。C++標準庫爲我們方便操作流對象定義了一些方法。

      I/O Library Header Files

      There are following header files important to C++ programs −

      

Sr.No       Header File & Function and Description
1

<iostream>

This file defines the cin, cout, cerr and clog objects, which correspond to the standard input stream, the standard output stream, the un-buffered standard error stream and the buffered standard error stream, respectively.

2

<iomanip>

This file declares services useful for performing formatted I/O with so-called parameterized stream manipulators, such as setw and setprecision.這個是用來控制數據輸出的格式,比如一個整數一共佔幾位,向左對齊還是向右對齊。一個小數一共輸出多少個有效位,小數點後輸出多少位等。具體後面代碼Demo

3

<fstream>

This file declares services for user-controlled file processing. We will discuss about it in detail in File and Stream related chapter.這個在後面講:“Input/output with files”時再詳細討論

      The Standard Output Stream (cout):標準輸出流,The predefined object cout is an instance of ostream class. The cout object is said to be "connected to" the standard output device, which usually is the display screen. The cout is used in conjunction with the stream insertion operator, which is written as << which are two less than signs

#include <iostream>
 
using namespace std;
 
int main() {
   char str[] = "Hello C++";
 
   cout << "Value of str is : " << str << endl;
}

      The Standard Input Stream (cin):標準輸入流,The predefined object cin is an instance of istream class. The cin object is said to be attached to the standard input device, which usually is the keyboard. The cin is used in conjunction with the stream extraction operator, which is written as >> which are two greater than signs

#include <iostream>
 
using namespace std;
 
int main() {
   char name[50];
 
   cout << "Please enter your name: ";
   cin >> name;
   cout << "Your name is: " << name << endl;
 
}

      The Standard Error Stream (cerr):標出錯誤流,The predefined object cerr is an instance of ostream class. The cerr object is said to be attached to the standard error device, which is also a display screen but the object cerr is un-buffered and each stream insertion to cerr causes its output to appear immediately.(非緩衝

#include <iostream>
 
using namespace std;
 
int main() {
   char str[] = "Unable to read....";
 
   cerr << "Error message : " << str << endl;
}

      The Standard Log Stream (clog):標準日誌流,The predefined object clog is an instance of ostream class. The clog object is said to be attached to the standard error device, which is also a display screen but the object clog is buffered. This means that each insertion to clog could cause its output to be held in a buffer until the buffer is filled or until the buffer is flushed.(有緩衝

#include <iostream>
 
using namespace std;
 
int main() {
   char str[] = "Unable to read....";
 
   clog << "Error message : " << str << endl;
}

你可能無法看到cout,cerr和clog與這些小例子有任何區別,但在編寫和執行大程序時,差異變得明顯。因此,最好使用cerr流顯示錯誤消息,並在顯示其他日誌消息時應使用clog。

格式化輸出的一些例子:

/*C++中格式化控制,略複雜,需要頭文件<iomanip>*/
#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
    printf("%5c\n%5d\n%6.2f\n", 'a', 100, 120.00);
    /*設置域寬(默認右對齊)及位數*/
    cout<<setw(5)<<'a'<<endl<<setw(5)<<100<<endl
       <<setprecision(2)<<setiosflags(ios::fixed)<<120.0<<endl;

    /*按進制輸出*/
    int i = 10;
    cout<<i<<endl;
    cout<<dec<<i<<endl; //10
    cout<<hex<<i<<endl; //a
    cout<<oct<<i<<endl; //12
    cout<<setbase(16)<<i<<endl; //a

    /*設置填充符,設置域寬的同時,設置左右對齊及填充符*/
    cout<<setbase(10);  //setbase需要在打印前重新進行設置
    cout<<setw(10)<<1234<<endl;
    cout<<setw(10)<<setfill('0')<<1234<<endl;   //00000001234
    cout<<setw(10)<<setfill('0')<<setiosflags(ios::left)<<1234<<endl;   //12340000000
    cout<<setw(10)<<setfill('-')<<setiosflags(ios::right)<<1234<<endl;  //-------1234
    cout<<888<<endl;
    return 0;
}

Input/output with files: 

      C++ provides the following classes to perform output and input of characters to/from files: 

     ofstreamStream class to write on files(寫文件)

     ifstreamStream class to read from files(讀文件)

     fstreamStream class to both read and write from/to files.(讀寫文件)

      看一個簡單的例子:

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    ofstream myfile;
    myfile.open("example.txt"); //文件不存在則創建
    myfile<<"Writing this to a file.\n";    //向文件中寫入一句話
    myfile.close();

    return 0;
}

      打開一個文件時,還可以指定打開的方式(只讀、只寫、是否覆蓋、是否追加)等。

      

//下面幾種情況會導致刷緩衝
//1. 程序正常結束,作爲 main 函數結束的一部分, 將清空所有緩衝區
//2. 緩衝區滿,則會刷緩衝
//3. endl, flush 也會刷緩衝
#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    fstream fs("abc.txt", ios::in | ios::out | ios::trunc);
    if(!fs){
        cout<<"error"<<endl;
    }
    fs<<1<<" "<<2<<" "<<3;  //重載<< >> 寫文件
    fs.seekg(0, ios::beg);

    int x, y, z;
    fs>>x>>y>>z;    //文件內容讀到x y z

    cout<<x<<y<<z;  //123
    return 0;
}

      

ios::in Open for input operations.
ios::out Open for output operations.
ios::binary Open in binary mode.
ios::ate Set the initial position at the end of the file.
If this flag is not set, the initial position is the beginning of the file.
ios::app All output operations are performed at the end of the file, appending the content to the current content of the file.
ios::trunc If the file is opened for output operations and it already existed, its previous content is deleted and replaced by the new one.

      上述表中的flags可以組合使用,正如上例所示。

      

class default mode parameter
ostream ios::out
istream ios::in
fstream ios::out | ios::in

      再看幾個例子:

            

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    ofstream myfile("example.txt");
    if(myfile.is_open()){
        myfile<<"This is a line.\n";
        myfile<<"This is another line.\n";
        myfile.close();
    }else{
        cout<<"Unable to open file";
    }

    return 0;
}
//從文件中讀取數據
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main()
{
    string line;
    ifstream myfile("example.txt");
    if(myfile.is_open()){
        while(getline(myfile, line)){
            cout<< line <<'\n';
        }
        myfile.close();
    }else{
        cout<<"Unable to open file";
    }

    return 0;
}

//執行結果:
//This is a line.
//This is another line.

我們還可以通過以下方法來檢查流的狀態:(比如讀寫是否異常,是否讀到文件的末尾了)

      bad()

Returns true  if a reading or writing operation fails. For example, in the case that we try to write to a file that is not open for writing or if the device where we try to write has no space left

      fail()

Returns true in the same cases as bad(), but also in the case that a format error happens, like when an alphabetical character is extracted when we are trying to read an integer number.

      eof()

Returns true if a file open for reading has reached the end.

      good()

It is the most generic state flag: it returns false in the same cases in which calling any of the previous functions would return true. Note that good and bad are not exact opposites (good checks more state flags at once).


The member function clear() can be used to reset the state flags.

我們還可以通過一下方法來判斷當前流的操作位置:

tellg() and tellp()

      These two member functions with no parameters return a value of the member type streampos, which is a type representing the current get position (in the case of tellg) or the put position (in the case of tellp).

seekg() and seekp()

      These functions allow to change the location of the get and put positions. Both functions are overloaded with two different prototypes. The first form is:

seekg ( position );
seekp ( position );


      Using this prototype, the stream pointer is changed to the absolute position position (counting from the beginning of the file). The type for this parameter is streampos, which is the same type as returned by functions tellg and tellp.

The other form for these functions is:

seekg ( offset, direction );
seekp ( offset, direction );

      Using this prototype, the get or put position is set to an offset value relative to some specific point determined by the parameter directionoffset is of type streamoff. And direction is of type seekdir, which is an enumerated type that determines the point from where offset is counted from, and that can take any of the following values:

      

ios::beg offset counted from the beginning of the stream
ios::cur offset counted from the current position
ios::end offset counted from the end of the stream

      下面通過以上特性方法我們來求一個文件的大小

      

//通過對流操作定位來計算文件大小
#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    streampos begin, end;
    ifstream myfile("F:\\QtProj\\IO_Stream_B\\example.bin", ios::binary);
    begin = myfile.tellg();
    myfile.seekg(0, ios::end);
    end = myfile.tellg();
    myfile.close();
    cout<<" size is: "<<(end-begin)<<"bytes.\n";    //文件的大小多少個字節
    return 0;
}

對於二進制文件的操作有些需要注意的:

      For binary files, reading and writing data with the extraction and insertion operators (<< and >>) and functions like getline is not efficient, since we do not need to format any data and data is likely not formatted in lines.
      File streams include two member functions specifically designed to read and write binary data sequentially: write and read. The first one (write) is a member function of ostream (inherited by ofstream). And read is a member function of istream (inherited by ifstream). Objects of class fstream have both. Their prototypes are:   
      write ( memory_block, size );
      read ( memory_block, size );

// reading an entire binary file
#include <iostream>
#include <fstream>
using namespace std;

int main () {
  streampos size;
  char * memblock;

  ifstream file ("example.bin", ios::in|ios::binary|ios::ate);    //流操作位置初始到文件末尾
  if (file.is_open())
  {
    size = file.tellg();    //獲取到文件的大小
    memblock = new char [size];
    file.seekg (0, ios::beg);
    file.read (memblock, size);
    file.close();

    cout << "the entire file content is in memory";

    delete[] memblock;
  }
  else cout << "Unable to open file";
  return 0;
}

基礎知識補充:

計算機處理的數據項構成的數據層次:

      位--------字段--------記錄----------文件-----------database--------------DBMS

 

C++中文件是無結構的,因此,程序員

C++將每個文件都視爲有序的字節流,每個文件或者以文件尾標識結束,或者在特定的字節號處結束。當打開一個文件時,就會創建一個對象,且一個 就會與這個 對象 相關聯。與對象相關的流,提供了程序與特定的文件或設備溝通的通道必須結構化文件,以滿足程序的要求

文件類型:

1、文本文件

      是以字符編碼的方式進行保存的,只是計算機以二進制表示數據在外部存儲介質上的另一種存放形式

2、二進制文件

      二進制文件適用於 非字符爲主 的數據。,除了文本文件外,所有的數據都可以算是二進制文件.二進制文件的

優點在於存取速度快,佔用空間小,以及可隨機存取數據

      在文件操作中因爲文本打開方式和二進制文件打開方式會導致數據讀取和寫入換行時候的不同所以在進行文件操作時候要注意寫入和讀取的方式要保持一致,如果採用文本方式寫入,應該採用文本方式讀取,如果採用二進制方式寫入,就應該用二進制方式讀取,但是不管是文本文件還是二進制文件,如果採用統一的二進制方式寫入和讀取數據都是不會出錯的,不管是文本文件還是二進制文件,都可以採用二進制方式或者文本方式打開,然後進行寫入或讀取。

 

文件存取方式:

1、順序讀取

也就是從上往下,一筆一筆讀取文件的內容

2、隨機存取

多半以二進制文件爲主.它會以一個完整的單位來進行數據的讀取和寫入,通常以結構爲單位

結語:針對IO操作,如果是Linux環境的系統編程,又可以單獨講一篇了,預計後續單獨寫一篇。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章