C++ 入門指南 - 存檔與載入

我們要存檔,儲存的到底是什麼呢?物件 (object) 嗎?變數成員 (variable member) 嗎?還有函數成員 (function member) 呢?




如果某次編碼結果不錯,我們往後想要繼續利用同一個 Encrypt 物件,這時候就需要把 Encrypt 物件儲存下來。想一想我們存檔應該儲存什麼?把整個 Encrypt 物件都儲存下來,還是只要儲存編碼用的 cArray 就可以了呢?


簡單一點,就儲存 cArray 就可以了,只是這樣 Encrypt 類別 (class) 需要多一個 setcArray() ,直接以載入的 cArray ,也就是用字串 (string) 當參數 (parameter) 設定 GUIDemo 類別的 e


這不難,增加一個 setcArray() 就夠了,因此 Encrypt.h 要加進以下函數成員的宣告
void setcArray(string);


然後 Encrypt.cpp 也要實作 setcArray(string)
void Encrypt::setcArray(string s) {
    cArray = s;
}


記得 Encrypt.h 跟 Encrypt.cpp 都要作修改。接下來看到存檔的 saveEncrypt() 與載入用的 loadEncrypt() ,我們要在 GUIDemo.h 加入這兩個函數成員的宣告,修改過後的 GUIDemo.h 如下
#ifndef GUIDEMO_H
#define GUIDEMO_H

#include <QWidget>
#include "Encrypt.h"

class QLabel;
class QLineEdit;
class QPushButton;

class GUIDemo : public QWidget {
    Q_OBJECT

public:
    GUIDemo(QWidget *parent = 0);
    QString s2q(const string &);  
    string q2s(const QString &);

public slots:
    void newEncrypt();
    void loadEncrypt();
    void saveEncrypt();
    void encodeContact();
    void decodeContact();
    void inputContact();

private:
    QLabel *display;
    QLineEdit *inputField;
    QLineEdit *outputField;
    QPushButton *newButton;
    QPushButton *loadButton;
    QPushButton *saveButton;
    QPushButton *encodeButton;
    QPushButton *decodeButton;
    QPushButton *clearButton;
    QPushButton *copyButton;
    
    QString inputText;
    QString outputText;    
    Encrypt *e;
};

#endif

/* 《程式語言教學誌》的範例程式
    http://pydoing.blogspot.com/
    檔名:GUIDemo.h
    功能:示範 C++ 程式 
    作者:張凱慶
    時間:西元 2012 年 10 月 */


實做 saveEncrypt() 與 loadEncrypt() 需要用到 QFile 與 QDataStream ,因此 GUIDemo.cpp 的開頭要先引入這兩個程式庫 (library)
#include <QFile>
#include <QDataStream>


saveEncrypt() 如下,當然,如果已經建立 e 才會儲存,如果沒有按過 New 按鈕,就會顯示提示訊息,然後什麼都不會做
void GUIDemo::saveEncrypt() {
    if (e != NULL) {
        QFile file("encryptor");
        file.open(QIODevice::WriteOnly);
        QDataStream out(&file);
        out << s2q(e->getcArray());
        
        display->setText("This is Save button. Encrypt object is saved.");
    }
    else {
        display->setText("This is Save button. There is no Encrypt Object.");
    }
}


存檔過程先是建立 QFile 型態的檔案處理物件 file ,檔名設定為 "encryptor" ,然後呼叫 open() 設定為寫入資料,接著建立 QDataStream 型態的資料串流處理物件 out ,最後以輸出串流運算子將 e 的 cArray 轉換成 QString 儲存到檔案中。


這裡要留意
QDataStream out(&file);


& 為取址運算子,這會取得 file 的記憶體位址,也就是指標 (pointer) 。


loadEncrypt() 的設計雷同,會先判斷 encryptor 檔案是否存在,檔案存在才會繼續進行載入的動作,如果沒有檔案,也就是之前使用沒有按過 Save 按鈕,同樣顯示提示訊息,然後什麼都不會做
void GUIDemo::loadEncrypt() {
    QFile file("encryptor");
    if (file.open(QIODevice::ReadOnly)) {
        QDataStream in(&file);
        QString temp;
        in >> temp;
        
        if (e == NULL) {
            e = new Encrypt;
            e->setcArray(q2s(temp));
        }
        else {
            e->setcArray(q2s(temp));
        }
        
        display->setText("This is Load button. Encrypt object is loaded.");
    }
    else {
        display->setText("This is Load button. Encrypt object is not loaded.");
    }    
}


載入過程先是建立 QFile 型態的檔案處理物件 file ,檔名預設為 "encryptor" ,然後呼叫 open() 設定為唯讀,接著建立 QDataStream 型態的資料串流處理物件 in ,最後以輸入串流運算子讀取 QString ,最後將 QString 轉換為 string 設定給 e 的 cArray 。


完整的實作檔 GUIDemo.cpp 如下,記得要把 SaveLoad 兩個按鈕建立 connect
#include <QtGui>
#include "GUIDemo.h"
#include <QFile>
#include <QDataStream>

GUIDemo::GUIDemo(QWidget *parent) : QWidget(parent) {
    QLabel *input = new QLabel(tr("Input:"));
    QLabel *output = new QLabel(tr("Output:"));
    display = new QLabel(tr("something happened"));
    
    inputField = new QLineEdit;
    connect(inputField, SIGNAL(returnPressed()), this, SLOT(inputContact()));
    outputField = new QLineEdit;
    outputField->setReadOnly(true);
    
    newButton = new QPushButton(tr("New"));
    connect(newButton, SIGNAL(clicked()), this, SLOT(newEncrypt()));
    loadButton = new QPushButton(tr("Load"));
    connect(loadButton, SIGNAL(clicked()), this, SLOT(loadEncrypt()));
    saveButton = new QPushButton(tr("Save"));
    connect(saveButton, SIGNAL(clicked()), this, SLOT(saveEncrypt()));
    encodeButton = new QPushButton(tr("Encode"));
    connect(encodeButton, SIGNAL(clicked()), this, SLOT(encodeContact()));
    decodeButton = new QPushButton(tr("Decode"));
    connect(decodeButton, SIGNAL(clicked()), this, SLOT(decodeContact()));
    clearButton = new QPushButton(tr("Clear"));
    copyButton = new QPushButton(tr("Copy"));
    
    QGridLayout *layout = new QGridLayout;
    
    layout->addWidget(input, 0, 0);
    layout->addWidget(inputField, 0, 1, 1, 6, 0);
    
    layout->addWidget(output, 1, 0);
    layout->addWidget(outputField, 1, 1, 1, 6, 0);
    
    layout->addWidget(newButton, 2, 0);
    layout->addWidget(loadButton, 2, 1);
    layout->addWidget(saveButton, 2, 2);
    layout->addWidget(encodeButton, 2, 3);
    layout->addWidget(decodeButton, 2, 4);
    layout->addWidget(clearButton, 2, 5);
    layout->addWidget(copyButton, 2, 6);
    
    layout->addWidget(display, 3, 0, 1, 7, 0);
    
    setLayout(layout);
    setWindowTitle(tr("GUIDemo"));
    
    e = NULL;
}

void GUIDemo::newEncrypt() {
    e = new Encrypt;
    display->setText("This is New button. Encrypt code is " + s2q(e->getcArray()));
}

void GUIDemo::loadEncrypt() {
    QFile file("encryptor");
    if (file.open(QIODevice::ReadOnly)) {
        QDataStream in(&file);
        QString temp;
        in >> temp;
        
        if (e == NULL) {
            e = new Encrypt;
            e->setcArray(q2s(temp));
        }
        else {
            e->setcArray(q2s(temp));
        }
        
        display->setText("This is Load button. Encrypt object is loaded.");
    }
    else {
        display->setText("This is Load button. Encrypt object is not loaded.");
    }    
}

void GUIDemo::saveEncrypt() {
    if (e != NULL) {
        QFile file("encryptor");
        file.open(QIODevice::WriteOnly);
        QDataStream out(&file);
        out << s2q(e->getcArray());
        
        display->setText("This is Save button. Encrypt object is saved.");
    }
    else {
        display->setText("This is Save button. There is no Encrypt Object.");
    }
}

void GUIDemo::encodeContact() {
    inputText = inputField->text();
    
    if (inputText == "") {
        display->setText("This is Encode button. No input string!!");
    }
    else {
        if (e == NULL) {
            display->setText("This is Encode button. No Encrypt object!!");
        }
        else {
            outputText = s2q(e->toEncode(q2s(inputText)));
            outputField->setText(outputText);
            display->setText("This is Encode button. The result is above.");
        }
    }
}

void GUIDemo::decodeContact() {
    inputText = inputField->text();
    
    if (inputText == "") {
        display->setText("This is Encode button. No input string!!");
    }
    else {
        if (e == NULL) {
            display->setText("This is Encode button. No Encrypt object!!");
        }
        else {
            outputText = s2q(e->toDecode(q2s(inputText)));
            outputField->setText(outputText);
            display->setText("This is Decode button. The result is above.");
        }
    }
}

void GUIDemo::inputContact() {
    inputText = inputField->text();
    display->setText("Your input is '" + inputText + "'.");
}

QString GUIDemo::s2q(const string &s) {  
    return QString(QString::fromLocal8Bit(s.c_str()));  
}  

string GUIDemo::q2s(const QString &s) {  
    return string((const char *)s.toLocal8Bit());  
} 

/* 《程式語言教學誌》的範例程式
    http://pydoing.blogspot.com/
    檔名:GUIDemo.cpp
    功能:示範 C++ 程式 
    作者:張凱慶
    時間:西元 2012 年 10 月 */


重新編譯執行,先建立一個 Encrypt ,下面是編碼結果,然後按 Save



換成其他的 Encrypt ,新的編碼結果



Load 載入,會得到儲存 Encrypt 的編碼結果囉



好了,下面我們繼續把功能建置完成,來看看完成版的 GUIDemo 吧!


中英文術語對照
物件object
變數成員variable member
函數成員function member
類別class
字串string
參數parameter
程式庫library
指標pointer


您可以繼續參考
GUI 篇


相關目錄
回 C++ 入門指南
回 C++ 教材目錄
回首頁


參考資料
Qt Developer Network

沒有留言: