ファイル入出力

メニューの設定とファイルの入出力です。

前田稔(Maeda Minoru)の超初心者のプログラム入門

FileClass

  1. 次のステップとして、メニューを設定してファイルの入出力を行います。
    今回開くファイルは一個だけですが、本来は TabControl で複数のファイルを同時に開く予定です。
    そこで FileClass を使ってファイルを一元管理することにします。
    File の入力は Text File の入力 を、 File の出力は Text File の出力 を参照して下さい。
    Object Class は gcmlcm Class を定義 を参照して下さい。
  2. ファイルを管理する class FileClass です。
    Form1.cs の class Form1 の後に定義して下さい。
    path がファイルのパスで、file がそのファイル名です。
    code はファイルの TEXT コード(UTF8, Shift-JIS など)です。
    str はファイルから入力した TEXT データです。
    行関係のメソッドは、行のコピーや削除及び、インデント処理に必要です。
    lstr はカーソルが設定されている現在行の文字列です。
    cursor がカーソル位置で、line が現在の行番号です。
    st, nx は現在行と次の行の先頭 Index です。
    lt はインデント処理に使う有効文字の位置です。
    reader, writer はファイル入出力のハンドルで、クラス全体で1個あれば良いので static で宣言しています。
    Constructor でファイルのパスと TEXT コードを受け取ります。
    ReadFile() メソッドでファイルを入力します。
    TEXT コードを指定して入力するメソッドと、既定のコードで入力するメソッドを定義します。
    これはもし間違ったコードで入力して文字化けするとき、読み直すためです。
    WriteFile() メソッドでファイルに出力します。
    上書き保存と、別名で保存に対応するメソッドを用意しています。
    TextWrite() メソッドで RichTextBox のデータを実際にファイルに書き出します。
    SetFile() はパスからファイル名を抜き出すメソッドです。
    Load() メソッドで str の TEXT データを RichTextBox に設定します。
    Save() メソッドで RichTextBox の TEXT を str に格納します。
    LineEdit() メソッドで現在行の情報を取得します。
    
        //★ Text File Class
        public class FileClass
        {
            public string   path;       //ファイルパス
            public string   file;       //ファイル名
            public string   code;       //TEXTコード
            public string   str;        //編集 TEXT
    
            public int      cursor;     //現在のカーソル位置
            public int      line;       //現在の行番号
            public string   lstr;       //現在行の文字列
            public int      st, nx;     //現在行と次の行の先頭Index
            public int      lt;         //次の行の有効文字
            static StreamReader   reader;
            static StreamWriter   writer;
    
            // Constructor
            public FileClass(string tpath, string tcode)
            {
                path = tpath;
                code = tcode;
                str = string.Empty;
                SetFile();
            }
    
            // Text File を入力
            public void ReadFile(string tcode)
            {
                code = tcode;
                ReadFile();
            }
            public void ReadFile()
            {
                if (code==string.Empty)
                    reader = new StreamReader(path);
                else
                    reader = new StreamReader(path, Encoding.GetEncoding(code));
                str = reader.ReadToEnd();
                reader.Close();
            }
    
            // Text File に保存
            public void WriteFile(RichTextBox textbox)
            {
                TextWrite(textbox, path, code);
            }
            public void WriteFile(RichTextBox textbox, string tpath, string tcode)
            {
                TextWrite(textbox, tpath, tcode);
                path = tpath;
                code = tcode;
                SetFile();
            }
            // RichTextBox のデータをファイル(tpath)に出力
            private void TextWrite(RichTextBox textbox, string tpath, string tcode)
            {
                if (tcode==string.Empty)
                    writer = new StreamWriter(tpath, false);
                else
                    writer = new StreamWriter(tpath, false, Encoding.GetEncoding(tcode));
                writer.Write(textbox.Text);
                writer.Close();
            }
            private void SetFile()
            {
                int i;
                i = path.LastIndexOf('\\');
                if (i > 0) file = path.Substring(i + 1);
                else file = path;
            }
    
            // RichTextBox ← 編集データ(str)
            public void Load(RichTextBox textbox)
            {
                textbox.Clear();
                textbox.Text = str;
            }
            // 編集データ(str) ← RichTextBox
            public void Save(RichTextBox textbox)
            {
                str = string.Empty;
                str = textbox.Text;
            }
    
            // 現在行を取得
            public void LineEdit(RichTextBox txtbox)
            {
                cursor = txtbox.SelectionStart;
                st = txtbox.GetFirstCharIndexOfCurrentLine();
                line = txtbox.GetLineFromCharIndex(st);
                if (line < (txtbox.Lines.Length-1))
                {
                    nx = txtbox.GetFirstCharIndexFromLine(line + 1);
                    lstr = txtbox.Text.Substring(st, nx - st);
                }
                else
                {
                    nx = st;
                    lstr = "*LineEdit EndLine";
                }
                for (lt=0; lt<lstr.Length; lt++)
                {
                    if (lstr[lt] == ' ') continue;
                    if (lstr[lt] == '\t') continue;
                    break;
                }
            }
        }
    

入出力メニュー

  1. Text Editor の開発では、簡単なメニューしか設定しませんでしたが、今回は本格的なメニューを設定します。
    ToolBox からメニューを貼り付ける を参照して下さい。
    全てのメニューのイベントハンドラも、ここで作成しておいて下さい。
    メニューの定義は Form1.Designer.cs で、イベントハンドラは Form1.cs に作成されます。
    UniOpen は、UTF8 と UniCode のどちらのファイルも入力出来ます。
    OverWrite は、入力したコードでファイルを上書きします。
    Undo は、編集操作の取り消しで、Redo はやり直しです。
    KeySearch は TEXT の検索機能で、Replace は文字列の置き換えです。
    Exec は、編集中のファイルを既定のプログラムで実行する機能で、私は HTML ファイルを編集しながらブラウザから起動するときに良く使います。
    Ut8Load, UniLoad, JisLoad, EucLoad は、文字化けするときコードを指定して読み直します。
    グループ メニュー メソッド
    File(&F)UniOpen(&O)UniOpen メソッド
    JisOpen(&P)JisOpen メソッド
    EucOpen(&Q)EucOpen メソッド
    OverWrite(&W)OverWrite メソッド
    Ut8Save(&8)Ut8Save メソッド
    UniSave(&U)UniSave メソッド
    JisSave(&J)JisSave メソッド
    EucSave(&E)EucSave メソッド
    FileClose(&C)FileClose メソッド
    Exit(&X)Exit メソッド
    Edit(&E)Copy(&C)Copy メソッド
    Cut(&T)Cut メソッド
    Paste(&P)Paste メソッド
    Undo(&U)Undo メソッド
    Redo(&R)Redo メソッド
    Tool(&T)KeySearch(&K)KeySearch メソッド
    Replace(&R)Replace メソッド
    View(&V)Exec(&E)Exec メソッド
    SetFont(&F)SetFont メソッド
    TextCode(&T)Ut8Load(&8)Ut8Load メソッド
    UniLoad(&U)UniLoad メソッド
    JisLoad(&J)JisLoad メソッド
    EucLoad(&E)EucLoad メソッド
    Help(&H)Version(&A)HelpAbout メソッド
  2. 今回はファイル入出力関係のコーディングで、他のメニューはこの後で説明します。
    ファイル入出力は FileClass のメソッドを利用します。
    元のソースと比べて、二重にならないように using を追加して下さい。
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Text;          // for Encoding
    using System.IO;            // for File, StreamReader
    
    public class Form1 : Form
    {
        FileClass   m_fclass;               // 編集中の File Class
        bool        m_flag;                 // Text 更新フラグ
        string      m_szDir = @"C:\tmp";    // 検索フォルダの初期値
    
  3. File Open 関係のメソッドです。
    OpenFileDialog でファイルを選択して、LoadFile で RichTextBox に表示します。
        // Open Menu
        private void UniOpen(object sender, EventArgs e)
        {
            OpenFile(string.Empty);
        }
        private void JisOpen(object sender, EventArgs e)
        {
            OpenFile("shift_jis");
        }
        private void EucOpen(object sender, EventArgs e)
        {
            OpenFile("euc-jp");
        }
    
        private void OpenFile(string encode)
        {
            OpenFileDialog openFileDialog1 = new OpenFileDialog();
            openFileDialog1.Title = "ファイルを選択してください";
            openFileDialog1.Filter = "TEXT File|*.txt;*.htm;*.html;*.cs;*.cpp|ALL File|*.*";
            openFileDialog1.RestoreDirectory = false; //true;
            openFileDialog1.ShowReadOnly = true;
            openFileDialog1.ReadOnlyChecked = true;
            openFileDialog1.InitialDirectory = m_szDir;
    
            if (openFileDialog1.ShowDialog(this) == DialogResult.OK)
            {
                LoadFile(openFileDialog1.FileName, encode);
            }
            openFileDialog1.Dispose();
        }
    
        private void LoadFile(string tpath, string tcode)
        {
            if (!File.Exists(tpath))
            {
                Console.WriteLine("File NotFound: " + tpath);
                return;
            }
            m_szDir = tpath;
            this.Text = m_szDir;
            m_fclass = new FileClass(tpath,tcode);
            m_fclass.ReadFile();
            m_fclass.Load(richTextBox1);
            tabControl1.GetControl(0).Text = m_fclass.file;
            tabControl1.SelectTab(0);
        }
    
  4. File Save 関係のメソッドです。
    SaveFileDialog でセーブファイルを選択して、WriteFile で書き出します。
    また同時に Save メソッドで str を最新の RichTextBox の状態に更新します。
    m_flag はファイル(編集中の TEXT DATA)の更新フラグです。
        private void OverWrite(object sender, EventArgs e)
        {
            if (m_fclass != null)
            {
                m_fclass.WriteFile(richTextBox1);
                m_fclass.Save(richTextBox1);
            }
        }
        private void Ut8Save(object sender, EventArgs e)
        {
            SaveFile("utf-8");
        }
        private void UniSave(object sender, EventArgs e)
        {
            SaveFile("utf-16");
        }
        private void JisSave(object sender, EventArgs e)
        {
            SaveFile("shift_jis");
        }
        private void EucSave(object sender, EventArgs e)
        {
            SaveFile("euc-jp");
        }
    
        private void SaveFile(string encode)
        {
            if (m_fclass == null)   return;
            SaveFileDialog saveFileDialog1 = new SaveFileDialog();
            saveFileDialog1.Title = "保存するファイルを選択してください";
            saveFileDialog1.Filter = "TEXT File|*.txt;*.log|ALL File|*.*";
            saveFileDialog1.RestoreDirectory = true;
            if (saveFileDialog1.ShowDialog(this) == DialogResult.OK)
            {
                m_fclass.WriteFile(richTextBox1, saveFileDialog1.FileName, encode);
                tabControl1.GetControl(0).Text = m_fclass.file;
                m_fclass.Save(richTextBox1);
            }
            saveFileDialog1.Dispose();
            m_flag = false;
        }
    
  5. File Close と保存の確認です。
    m_flag はファイル(編集中の TEXT DATA)の更新フラグです。
        private void FileClose(object sender, EventArgs e)
        {
            if (Cancel_Check()) return;
            m_fclass.file = string.Empty;
            m_fclass.str = string.Empty;
            richTextBox1.Text = string.Empty;
        }
        private bool Cancel_Check()
        {
            DialogResult rc;
            if (m_flag)
            {
                rc = MessageBox.Show("保存しないで実行しますか", "選択",
                     MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                if (rc == DialogResult.No)  return true;
            }
            m_flag = false; 
            return false;
        }
    
  6. コンパイル&実行して、メニューから TEXT FILE を選択すると richTextBox1 に表示されます。
    編集メニューは設定されていませんが、TEXT を選択して Ctrl+C でクリップボードにコピーされます。
    コピーされた文字列は Ctrl+V でペーストすることが出来ます。

【NOTE】

バイナリエディッタで調べれば解るのですが、Unicode(utf-16)の先頭2バイトには次のコードが格納されています。
FFFE
これが Unicode ファイルの識別コードになっていて、encode の指定より優先されるようです。
従って、Unicode ファイルはコードを指定して読み込んでも、"utf-16" で入力されます。
C# のファイルは、規定値では "utf-8" で保存されます。
"utf-8" はこのような識別コードは無く、他のコードを指定して読み込むと文字化けします。
文字コードを意識しないで、文字化けを避けるには "utf-16" が適しているようです。

[Next Chapter ↓] Contex Menu
[Previous Chapter ↑] Text Editor の開発

超初心者のプログラム入門(C# Frame Work)