涼の成長記録

自らの人生に主導権を持つべく、独立を目指して2014年3月31日を持ってITエンジニアを退職。そんな23歳♂の成長記録。

CSVファイルアクセスクラス

良さげなものがWEBで見つからなかったので、自分で無理矢理作ってみる。

※ 2013年11月25日
以下の記事もご覧になった方が良いかもしれません。
TStrings::CommaTextは半角スペースも区切り文字とみなす - 涼の成長記録



TCsvFileAccess.h

/*!
    @file   TCsvFileAccess.h
    @brief  CSVファイルアクセスクラスの宣言
*/

#ifndef TCsvFileAccessH
#define TCsvFileAccessH

#include <vector>

namespace Common {
namespace FileAccess {

//! [縦][横]の2次元配列。
typedef std::vector<std::vector<UnicodeString> > CSV_VECTOR;
//                                            ↑スペースが無いとシフト演算子に優先度負ける。

/*!
    CSVファイルアクセスクラス

    CSVファイルアクセスを行うクラスのベースとしてヘルパーを担う。
    コンストラクターでファイルのパスを渡して、
    read(), write()メソッドで、指定のフィールドへアクセスする。

    @note   TStringListはVCL特有のクラスであるため、VC++等に対しての移植性は無い。
            将来的には、fstream等を使って実装してみたい。。
*/
class TCsvFileAccess {
    public:
        /*!
            コンストラクター

            @param  filePath    :CSVファイルのパス
        */
        __fastcall TCsvFileAccess(const UnicodeString &filePath);

        /*!
            仮想デストラクター
        */
        virtual __fastcall ~TCsvFileAccess();

        /**
            コンストラクターで渡されたファイルパスが存在すればtrueを返す。

            @return ファイルがあればtrue。なければfalse。
         */
        bool __fastcall isFileExist();

        /*!
            読み込み。

            ファイルが無ければ、デフォルト値を書込む。

            @param  array :読込んだデータを格納する2次元配列の参照。
                           そのサイズから、読込む行数と列数を取得するので、
                           取得しておきたい行数と列数分のサイズを確保しておくこと。
            @@return    正常時true。行数、列数が足りなかった場合等はfalse。
        */
        bool __fastcall read(CSV_VECTOR &array);

        /*!
            書き込み。

            2次元配列のarrayをコンマ区切りでCSVファイルへ出力する。

            @param  array :書込む2次元配列の参照
            @return なし。
        */
        void __fastcall write(const CSV_VECTOR &array);


    private:
        //! ファイル名称
        const UnicodeString m_FilePath;
};

}   // namespace FileAccess
}   // namespace Common

#endif

TCsvFileAccess.cpp

/*!
    @file   TCsvFileAccess.cpp
    @brief  CSVファイルアクセスクラスの実装
*/

#include <vcl.h>
#pragma hdrstop

#include <IOUtils.hpp>
#include <vector>
#include "TCsvFileAccess.h"

#pragma package(smart_init)

namespace Common {
namespace FileAccess {

//------------------------------------------------------------------------------
// コンストラクター
//------------------------------------------------------------------------------
__fastcall TCsvFileAccess::TCsvFileAccess(const UnicodeString &filePath) : m_FilePath(filePath) {
    // フォルダーを作成しておく。
    try {
        ForceDirectories(TPath::GetDirectoryName(m_FilePath));
    }
    catch (...) {
        // 例外もぐもぐ。。
    }
}

//------------------------------------------------------------------------------
// ファイルがあればtrueを返す
//------------------------------------------------------------------------------
bool __fastcall TCsvFileAccess::isFileExist() {
    return FileExists(m_FilePath);
}

//------------------------------------------------------------------------------
// 読み込み。
//------------------------------------------------------------------------------
bool __fastcall TCsvFileAccess::read(CSV_VECTOR &array) {
    // 読込むファイルが無ければ異常
    if (!FileExists(m_FilePath)) {
         return false;
    }

    TStringList *line = new TStringList;    // 一行分のデータ。
    TStringList *file = new TStringList;    // ファイル全体分のデータ。

    try {   // 項目数エラーや、異常値等で簡単に例外が発生する。
        file->LoadFromFile(m_FilePath);
        for (unsigned int i = 0; i < array.size(); i++) {
            line->CommaText = file->Strings[i];
            for (unsigned int j = 0; j < array.at(i).size(); j++) {
                array.at(i).at(j) = line->Strings[j];
            }
        }
    }
    catch (...) {
        delete line; delete file;
        return false;
    }

    delete line; delete file;
    return true;
}

//------------------------------------------------------------------------------
// 書き込み。
//------------------------------------------------------------------------------
void __fastcall TCsvFileAccess::write(const CSV_VECTOR &array) {
    TStringList *line = new TStringList;    // 一行分のデータ。
    TStringList *file = new TStringList;    // ファイル全体分のデータ。

    file->Clear();
    for (unsigned int row = 0; row < array.size(); row++) {
        line->Clear();
        for (unsigned int col = 0; col < array.at(row).size(); col++) {
            line->Add(array.at(row).at(col));
        }
        file->Add(line->CommaText);
    }
    file->SaveToFile(m_FilePath);

    delete line; delete file;
}

}   // namespace FileAccess
}   // namespace Common