從零開始學C++之IO流類庫(三):檔案的讀寫、二進位檔案的讀寫、檔案隨機讀寫

來源:互聯網
上載者:User

一、檔案的讀寫

如前面所提,流的讀寫主要有<<, >>, get, put, read, write 等操作,ofstream 繼承自ostream, ifstream 繼承自 istream,故操作函數都是一致的。

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
using namespace std;

int main(void)
{
    ofstream fout("test.txt");
    fout << "abc" << " " << 200;
    fout.close();

    ifstream fin("test.txt");
    string s;
    int n;
    //fin>>n>>s;
    fin >> s >> n;
    cout << s << " " << n << endl;

    ofstream fout1("test2.txt");
    assert(fout1);
    char ch;

    for (int i = 0; i < 26; i++)
    {
        ch = 'A' + i;
        fout1.put(ch);
    }
    fout1.close();

    ifstream fin1("test2.txt");
    while (fin1.get(ch))
    {
        cout << ch;
    }
    cout << endl;

    return 0;
}

二、二進位檔案的讀寫

二進位檔案不同於文字檔,它可用於任何類型的檔案(包括文字檔)
對二進位檔案的讀寫可採用從istream類繼承下來的成員函數read()和從ostream類繼承下來的成員函數write()
檔案開啟操作時使用枚舉常量ios::binary,例如:ofstream fout(“binary.dat”,ios::out | ios::binary);


(一)、write成員 函數

函數功能:以位元組位單位向檔案流中寫入整塊資料,最有價值的應用可以處理結構體變數和類對象
函數原型:

ostream& write( const char* pch, int nCount );

函數參數:
pch 寫入的資料的指標
nCount 寫入資料的位元組大小


(二)、read 成員 函數

函數功能:從檔案流中讀出整塊資料
函數原型:

istream& read( char* pch, int nCount ); 

函數參數:
pch 用來接收資料的指標
nCount 讀取的位元組數的大小


 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <cassert>
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

struct Test
{
    int a;
    int b;
};

int main(void)
{
    ofstream fout("test3.txt", ios::out | ios::binary); // 二進位方式開啟,'\n'不做轉換
    fout << "ABC\n"; // << 是以文本方式寫入
    fout.close();

    Test test = { 100, 200 };
    ofstream fout1("test4.txt", ios::out | ios::binary);
    fout1.write(reinterpret_cast<char *>(&test), sizeof(Test));
    // 二進位方式寫入後用文字編輯器開啟test4.txt 亂碼
    fout1.close();

    Test test2;
    ifstream fin("test4.txt", ios::in | ios::binary);
    fin.read(reinterpret_cast<char *>(&test2), sizeof(Test));
    cout << test2.a << " " << test2.b << endl;

    ofstream fout2("test5.txt", ios::out | ios::binary);
    fout2 << "abc" << 200; // << 是以文本方式寫入
    fcout2.close();

    return 0;
}

在window下以文本方式開啟檔案,則寫入時遇到'\n' , 轉換為'\r\n',以二進位方式開啟則不做轉換,故test3.txt 檔案大小為4個位元組。

而寫入100(write 是以二進位方式寫入)就不再是寫入'1', '0' ,' 0' 的ascii 碼,而是按照記憶體本來二進位形式寫入,故用文字編輯器開啟test4.txt 時會出現亂碼。檔案大小為8個位元組(兩個int)

同理,test5.txt 雖然以二進位開啟,但是以文本方式(<< 是以文本方式寫入)寫入的,故寫入200後用文字編輯器開啟不會出現亂碼,檔案大小為6個位元組。

有關文字檔與二進位檔案的區別,請參考這裡。


使用read, write 讀取string 的時候需要注意,string 實際上內部是一些指標成員,sizeof(string)=32 (跟編譯器實現有關),即string 大小是一定的,而它的指標成員儲存的字串長度不一定是32,故我們應該這些讀寫:

 C++ Code 
1
2
3
4
5
6
7
8
9
string str1 = "fdsfafsdsf";
int len = str1.length();
ofstream fout("test6.txt", ios::out | ios::binary);
fout.write(str1.data(), str1.length());

string str2;
str2.resize(len);
ifstream fin("test6.txt", ios::in | ios::binary);
fin.read(&str2[0], len);

如果像這樣寫入  fout.write((char*)&str1, sizeof(str1)); 一定是錯誤的,因為寫入的是str1 的指標成員,而不是指標成員指向的字串,而且str1 的大小恒等於32。


三、檔案隨機讀寫

(一)、當前檔案流活動指標

檔案流指標用以跟蹤發生 I/O 操作的位置
每當從流中讀取或寫入一個字元,當前活動指標就會向前移動
當開啟檔案中不含有ios::ate或ios::app選項時,則檔案指標被自動移到檔案的開始位置,即位元組地址為0的位置。


(二)、檔案的隨機讀寫 seekp和seekg

seekp 和 seekg 類似與C庫的fseek, linux系統調用的lseek。


函數功能

seekp:設定輸出檔案流的檔案流指標位置

seekg:設定輸入檔案流的檔案流指標位置

函數原型:

ostream& seekp( streampos pos );

ostream& seekp( streamoff off, ios::seek_dir dir );

istream& seekg( streampos pos );

istream& seekg( streamoff off, ios::seek_dir dir );

函數參數

pos:新的檔案流指標位置值

off:需要位移的值

dir:搜尋的起始位置

dir參數用於對檔案流指標的定位操作上,代表搜尋的起始位置
在ios中定義的枚舉類型:

enum seek_dir {beg, cur, end};

每個枚舉常量的含義:
ios::beg:檔案流的起始位置
ios::cur:檔案流的當前位置
ios::end:檔案流的結束位置


tellp 和 tellg 類似C庫的ftell,,linux 系統調用的lseek(fd, 0, SEEK_CUR);

函數功能

tellp:獲得輸出的檔案流指標的當前位置,以位元組為單位

tellg:獲得輸入的檔案流指標的當前位置,以位元組為單位

函數原型:

streampos tellp();

streampos tellg();

函數傳回值:實際上是一個long類型


 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <cassert>
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main(void)
{
    ifstream fin("test7.txt");
    assert(fin);
    fin.seekg(2);//位置從0開始計數

    char ch;
    fin.get(ch);
    cout << ch << endl;

    fin.seekg(-1, ios::end); //end 實際上是EOF位置
    fin.get(ch);
    cout << ch << endl;

    fin.seekg(0, ios::end);
    streampos pos = fin.tellg();
    cout << pos << endl;

    return 0;
}

假設test7.txt 現在存放abcdefg 7個字元,則輸出為c g 7 .


參考:

C++ primer 第四版
Effective C++ 3rd
C++編程規範

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.