[C++] テキストファイル読書き (C#プログラマ向け)

  • 1
    いいね
  • 4
    コメント

囲碁プログラムを これから書こうと思ってるんだが、
C# プログラマーには C++ がさっぱりわからん。

第1段階

テキスト・ファイルの入出力は これでいける感じだった。

Console_Kifuwarabe.cpp

// Console_Kifuwarabe.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include "UtilFile.h"

int main()
{
    std::cout << "Hello, World." << std::endl;

    UtilFile::Write("test.txt", "ほっほ☆(^▽^)\nどうだぜ☆(^~^)?");
    std::string contents = UtilFile::Read("test.txt");

    std::cout << contents << std::endl;

    // 横軸はアルファベットにする☆(1桁で済む) Iを飛ばすのは 少なくともわたしはグニュー碁1.2(1995年)では見かけた昔からある習慣☆ 縦棒と区別するぜ☆(^▽^)

    std::cout   << "  |ABCDEFGHJKLMNOPQRST|" << std::endl
                << "--+-------------------+" << std::endl
                << " 1|                   |" << std::endl
                << " 2|                   |" << std::endl
                << " 3|                   |" << std::endl
                << " 4|                   |" << std::endl
                << " 5|                   |" << std::endl
                << " 6|                   |" << std::endl
                << " 7|                   |" << std::endl
                << " 8|                   |" << std::endl
                << " 9|                   |" << std::endl
                << "10|                   |" << std::endl
                << "11|                   |" << std::endl
                << "12|                   |" << std::endl
                << "13|                   |" << std::endl
                << "14|                   |" << std::endl
                << "15|                   |" << std::endl
                << "16|                   |" << std::endl
                << "17|                   |" << std::endl
                << "18|                   |" << std::endl
                << "19|                   |" << std::endl
                << "--+-------------------+" << std::endl
                << "何かボタンを押せだぜ☆(^▽^)" << std::endl;
    getchar();
    //system("pause");

    return 0;
}

UtilFile.h

#pragma once

#include <iostream>
#include <string>
#include <fstream>

/**
 * テキストファイルの読書き
 * 参照 : 「[C++] ファイル入出力の覚書」 (Qiita) http://qiita.com/lazynick/items/8aede589bb9ca0c8b64f
 * 参照 : 「文字列の結合方法による速度差」 (Qiita) http://qiita.com/ampersand/items/0322e0820badf2c020be
 * 参照 : 空文字列で初期化するには : 「文字列の初期化」 (手を動かしてさくさく理解する C++ 文字列クラス std::string 入門) http://vivi.dyndns.org/tech/cpp/string.html
 */
class UtilFile
{
public:
    UtilFile();
    ~UtilFile();

    static void Write(std::string filename, std::string contents);

    static std::string Read(std::string filename);
};

UtilFile.cpp

#include "stdafx.h"
#include "UtilFile.h"


UtilFile::UtilFile()
{
}


UtilFile::~UtilFile()
{
}


void UtilFile::Write(std::string filename, std::string contents)
{
    std::ofstream writing_file;
    writing_file.open(filename);

    writing_file << contents;
}


std::string UtilFile::Read(std::string filename)
{
    // ファイルの内容全文
    std::string contents;

    std::ifstream file;
    file.open(filename);

    std::string line;
    while (!file.eof())
    {
        // 1行ずつ読み取ります
        std::getline(file, line);
        contents += line;

        // 次行があるなら改行を追加
        if (file.eof()) { contents += "\n"; }
    }

    return contents;
}

(2017-02-28 変更)writing_file.open(filename, std::ios::out); -> writing_file.open(filename);
(2017-02-28 変更)file.open(filename, std::ios::in); -> file.open(filename);

よし!

第2段階

コメント欄で C++ の一般的なやり方を 教えてもろた。

C# では めんどくさくなったら なんでもかんでもクラス にしておけば 何にも考えず 脳みそ真っ白プリンでいけるんだが、
人が成長できる時間というものには 人びとには公平には与えられていないタイミングのようなものがあり、自分だけが得をしているとか自意識過剰に考えることなく 伸びれるときに伸びておけ という鉄則がある。 じゃあ 伸びるか……。

UtilFile.h を書き換えてみよう。

UtilFile.h

#pragma once

#include <iostream>
#include <string>
#include <fstream>

/**
 * テキストファイルの読書き
 *
 * 自著 : [C++] テキストファイル読書き (C#プログラマ向け) (Qiita) http://qiita.com/muzudho1/items/fa1446b85ae64d01a5ca
 * 参照 : 「[C++] ファイル入出力の覚書」 (Qiita) http://qiita.com/lazynick/items/8aede589bb9ca0c8b64f
 * 参照 : 「文字列の結合方法による速度差」 (Qiita) http://qiita.com/ampersand/items/0322e0820badf2c020be
 * 参照 : 空文字列で初期化するには : 「文字列の初期化」 (手を動かしてさくさく理解する C++ 文字列クラス std::string 入門) http://vivi.dyndns.org/tech/cpp/string.html
 * 参照 : 「lambda式を引数として受け取る関数の自作はできますか?」 (Teratail) https://teratail.com/questions/37610
 */
namespace UtilFile
{
    /**
     * ファイルへ文字列を書き出します。
     */
    void Write(std::string filename, std::string contents);

    /**
     * ファイルから文字列を読み取ります。
     */
    std::string Read(std::string filename);
}

(2017-02-28 変更)namespace の } の後ろのセミコロン削除。

なんか .cpp の方は変えなくていいようだ。

なんか、C++ は いちいち ひとつひとつ この場合はこう、あの場合はこう、と覚えていかなくてはいけない感じが ぷんぷん と匂っている。

まあ、C# と 二足のわらじ を履けばいいのではないか。

第3段階

ファイルが読めなかったときの処理も 書くことにした。

UtilFile::Read の引数や返り値を改造することに。

bool UtilFile::Read(std::string filename, std::string& contents)
{
    std::ifstream file;
    file.open(filename);
    if (file.fail())
    {
        //std::cout << "ファイル[" << filename << "]が開けなかった☆(^~^)!オワタ~☆(>_<)" << std::endl;
        return false;
    }

    std::string line;
    while (!file.eof())
    {
        // 1行ずつ読み取ります
        std::getline(file, line);
        contents += line;

        // 次行があるなら改行を追加
        if (file.eof()) { contents += "\n"; }
    }

    return true;
}

ファイルが読めなかったら また 1秒後にリトライするとか 外側で書くことにしよう。