class//TxtFile

使用C++的STL容器vector,來串起一個.txt檔。
以'\n'來切割vector中的每一個容器元素多長。
(如果全部用一個CString,有時Buffer不足會導致錯誤)
檔案的讀取和儲存,則是使用MFC內建的CStdioFile,它的操作和標準C++處理檔案類別很像。

TxtFile.h

#ifndef TXTFILE_H
#define TXTFILE_H

#include <vector>

typedef std::vector<CString> TxtStrData;

class CTxtFile  
{
    CStdioFile ftxt_Std;
    TxtStrData dtxt_Txt;
public:
    CTxtFile(){};
    virtual ~CTxtFile(){};
    BOOL Open(LPCTSTR, CFileException&);
    BOOL Save(LPCTSTR, CFileException&);

    void Close(){ ftxt_Std.Close(); };

    void iTxtData(TxtStrData& data){ dtxt_Txt = data; mem2file(); };
    void oTxtData(TxtStrData& data){ file2mem(); data = dtxt_Txt; };
    TxtStrData oTxtData(){ file2mem(); return dtxt_Txt; };

private:
    void file2mem();
    void mem2file();
    void errorMsg(CFileException&);
};

#endif

TxtFile.cpp

檔案的讀寫

檔案讀寫,其實操作和C++原本的類別操作沒有兩樣。
只是要特別設計的地方在於「發生錯誤」的處理方式,是不是可以馬上顯示出正確的錯誤訊息。
BOOL CTxtFile::Open(LPCTSTR path, CFileException& fx)
{
    if (PathFileExists(path))
    {
        if (ftxt_Std.Open(path, CFile::modeRead | CFile::typeText, &fx))
            return TRUE;
        else
        { 
            errorMsg(fx);
            ftxt_Std.Close();
            return FALSE;  //失敗
        }
    }
    else
        return FALSE;
}

BOOL CTxtFile::Save(LPCTSTR path, CFileException& fx)
{
    if (ftxt_Std.Open(path, CFile::modeCreate | CFile::modeWrite | CFile::typeText, &fx))
        return TRUE;
    else
    {
        errorMsg(fx);
        ftxt_Std.Close();
        return FALSE;
    }
}

錯誤訊息的顯示

檔案做動作時,會出現的錯誤訊息
void CTxtFile::errorMsg(CFileException& fx)
{
    //例外處理
    TCHAR buf[255];
    fx.GetErrorMessage(buf, 255);
    CString strPrompt;
    strPrompt.Format("CTxtFile說:「%s」", buf);
    AfxMessageBox(strPrompt);
}

資料從硬體到記憶體的動作

資料在記憶體中如何存放,會是檔案讀寫的一個重點。
若格式太特殊,則此類別的再用率降低。反之亦然。
所以,在此就將這個設計規劃成獨立的function,可以再設計,讓source code的再用率做一個折衷。
在此設計的方式,是使用一個vector來儲存一整個純文字檔,以'\n'符號來做vector的每一個元素的分隔。巨觀來說就是純文字檔的每一行,存成每一個vector的元素,而每一個元素就是一個CString(MFC的字串)。每個字串的切割需求,可以用繼承的方式來利用這個類別的function。
void CTxtFile::file2mem()
{
    dtxt_Txt.clear();
    CString strTemp;
    while (ftxt_Std.ReadString(strTemp))
    {
        strTemp.Format(_T("%s\n"), strTemp);
        dtxt_Txt.push_back(strTemp);
    }
}

void CTxtFile::mem2file()
{
    if (!dtxt_Txt.empty())
    {
        for (TxtStrData::iterator it = dtxt_Txt.begin(); it != dtxt_Txt.end(); ++it)
            //AfxMessageBox(*it);
                ftxt_Std.WriteString(*it);
    }
}

文章分類維度