C#で作るWindowsアプリ
−ファイルを読み込む−


[トップ] [目次] [←前] [次→]

ファイルを読み込む

前々回のサンプルをファイル−開くメニューと開くボタンがクリックされたら実際にファイルを読み込んでテキストボックスに表示するようにしてみましょう。
今回もコードから(コードか長くなるので、前回のではなくSample2bと違うところを強調してます)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

namespace Sample4a {
    using System;
    using System.IO;
    using System.Drawing;
    using System.Windows.Forms;
    
    public class MyForm : Form {
        private TextBox mTextBox;               // テキストボックス
        private string mDefaultDirectory;      // カレントディレクトリ
        
        // Main
        public static void Main(string[] args) {
            MyForm frm = new MyForm();
            Application.Run(frm);
        }
        
        // コンストラクタ
        public MyForm() {
            // メインメニューを生成
            MainMenu mm = new MainMenu();
            
            // ファイルメニューを生成
            MenuItem mi = mm.MenuItems.Add("ファイル(&F)");
            mi.MenuItems.Add(new MenuItem("開く(&O)...", new EventHandler(this.FileOpen_Clicked)));
            mi.MenuItems.Add("-");
            mi.MenuItems.Add(new MenuItem("終了(&X)", new EventHandler(this.FileExit_Clicked), Shortcut.CtrlQ));
            
            // ヘルプメニューを生成
            mi = mm.MenuItems.Add("ヘルプ(&H)");
            mi.MenuItems.Add(new MenuItem("バージョン情報(&A)...", new EventHandler(this.HelpAbout_Clicked)));
            
            // フォームのメニューとしてセット
            this.Menu = mm;
            
            // 開くボタンを生成
            Button btn = new Button();
            btn.Text = "開く...";
            btn.Location = new Point(2, 2);    // 座標を設定
            btn.Size = new Size(100, 22);      // サイズを設定
            btn.TabIndex = 0;                  // タブ順は最初
            btn.Anchor = AnchorStyles.Top | AnchorStyles.Left;  // 左上を固定
            btn.Click += new EventHandler(this.FileOpen_Clicked);
            this.Controls.Add(btn);
            
            // テキストボックスを生成
            mTextBox = new TextBox();
            mTextBox.Text = "";
            mTextBox.Location = new Point(0, 26);   // 座標を設定
            mTextBox.Size = new Size(this.ClientSize.Width, this.ClientSize.Height - 26);
                                                     // サイズを設定
            mTextBox.Multiline = true;              // 複数行OKにする
            mTextBox.ScrollBars = ScrollBars.Both;  // スクロールバーを表示
            mTextBox.BackColor = Color.White;       // 背景色を白にする
            mTextBox.TabIndex = 1;                  // タブ順は2番目
            mTextBox.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
                                                     // 上下左右とも固定
            Controls.Add(mTextBox);
        }
        
        // ファイル−開くメニューのイベントハンドラ
        private void FileOpen_Clicked(object sender, EventArgs e) {
            OpenFileDialog opendlg = new OpenFileDialog();
            opendlg.Filter = "テキストファイル (*.txt)|*.txt|すべてのファイル (*.*)|*.*" ;
            opendlg.InitialDirectory = mDefaultDirectory;
            if (opendlg.ShowDialog() == DialogResult.OK) {
                // ディレクトリを保存しておく
                FileInfo fi = new FileInfo(opendlg.FileName);
                mDefaultDirectory = fi.DirectoryName;
                
                // ファイルを読み込む
                Stream stm = opendlg.OpenFile();
                if (stm != null) {
                    StreamReader reader = new StreamReader(stm);
                    mTextBox.Text = reader.ReadToEnd();
                    stm.Close();
                }
            }
        }
        
        // ファイル−終了メニューのイベントハンドラ
        private void FileExit_Clicked(object sender, EventArgs e) {
            this.Close();
        }
        
        // ヘルプ−バージョン情報メニューのイベントハンドラ
        private void HelpAbout_Clicked(object sender, EventArgs e) {
            MessageBox.Show("Sample3aプログラム Ver 0.1");
        }
    }
}
Sample4a.cs

コンパイル

csc /t:winexe /r:System.DLL /r:System.Windows.Forms.DLL /r:System.Drawing.DLL Sample4a.cs

これでコンパイルできるはずです。
ファイル名が違うだけでSample2と変わってません。

ファイルを開くダイアログを開く

62行目からがファイルを開くダイアログを開くコードです。
ファイルを開くダイアログはSystem.Windows.Forms.OpenFileDialogという、そのまんまのクラスが用意されています。 これを生成して、プロパティを設定して、ShowDialogメソッドを呼ぶだけです。

ここで、InitialDirectoryプロパティだけ一工夫しています。 これは、ファイルを開くダイアログを開いたときに、最初に表示するディレクトリを指定するプロパティですが、毎回変わってしまうのはいやなので前回のディレクトリをmDefaultDirectoryに覚えておいて、それをセットするようにしています。 mDefaultDirectory自体は、67、68行目で選択されたファイル名のディレクトリを代入してます。
ファイル名からディレクトリ名を取り出すのは、以前なら「\マークを後ろから探して...」なんてするところですが、FileInfoクラスを使えばそんなことは全部やってくれます。
(ほんとはカレントディレクトリが変わってるので、こんなことしなくてもいいんですが。まぁ、サンプルということで)

ファイルを読み込む

71行目からで実際にファイルを読み込んでます。
OpenFileDialogのOpenFileメソッドを使うと選択されたファイルのSystem.IO.Streamがもらえます。 リファレンスを見ればわかるように、StreamクラスのReadメソッドなんかを使えばファイルを読み込むことができます。
でも、このReadメソッドってbufferだ、offsetだってなんかややこしいですよね?
実は、もっと簡単にファイルを読み込むためのクラスSystem.IO.StreamReaderってのがあります。 こいつには「1文字だけ読み込むRead」「指定サイズだけ読み込むRead」「1行(改行まで)読み込むReadLine」「まるごと全部読み込むReadToEnd」なんてのがあって便利です。 StreamReaderのコンストラクタを見ればわかるとおり、Streamを受け取れるようになってます。 なので、73行目のようにOpenFileDialogのOpenFileメソッドでもらったStreamを渡してこさえてます。 あとは、ReadToEndメソッドで丸ごと読み込んでテキストボックスに放り込んでいるだけ。

まぁ、OpenFileメソッドを使わずにファイル名を使って、


StreamReader reader = new StreamReader(opendlg.FileName);

としてもいいんですが。
.NETでファイルの読み書きをするときは、こんな風に「なんかで作ったStreamを使ってStreamReaderをnewして...」 なんてすることが多いので、わざわざそうしてみました。

もちろん、書き込むときに便利なStreamWriter、バイナリファイルのときに便利なBinaryReader、BinaryWriterなんかも用意されています。 この辺はみんなSystem.IOネームスペースにありますからリファレンスを見てみてください。

その他の変更

3行目でusing SystemIO;してます。
読み込んだファイルを放り込むためにテキストボックスをメンバ変数として追いとくようにしました。
ファイル−開くメニューと開くボタンのイベントハンドラはまったく同じ内容になるので1つのメソッドで兼用するようにしました(42行目)。

さぁ完成...ありゃりゃ?

上のコードで実際にちゃんと動くんですが...
日本語(Shift_JIS)で書かれたファイルを読み込むと化け化けになっちゃいます。

そう、.NETな世界はすべてUnicodeなんです。 なので、Shift_JISのファイルなんて読み込めません。 読み込むんだったら、ちゃんとShift_JIS→Unicodeに変換してやらないといけないんです。


文字コード変換

と言っても、ちゃんと文字コード変換をするクラスが用意されています。
変更するのはファイルをオープンするところだけなので、その部分のみ抜粋します。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

        // ファイル−開くメニューのイベントハンドラ
        private void FileOpen_Clicked(object sender, EventArgs e) {
            OpenFileDialog opendlg = new OpenFileDialog();
            opendlg.Filter = "テキストファイル (*.txt)|*.txt|すべてのファイル (*.*)|*.*" ;
            opendlg.InitialDirectory = mDefaultDirectory;
            if (opendlg.ShowDialog() == DialogResult.OK) {
                // ディレクトリを保存しておく
                FileInfo fi = new FileInfo(opendlg.FileName);
                mDefaultDirectory = fi.DirectoryName;
                
                // ファイルを読み込む
                Stream stm = opendlg.OpenFile();
                if (stm != null) {
                    StreamReader reader = new StreamReader(stm, System.Text.Encoding.GetEncoding("Shift_JIS"));
                    mTextBox.Text = reader.ReadToEnd();
                    stm.Close();
                }
            }
        }
Sample4b.cs(抜粋)

そう、直さなくちゃいけないのはたった1ヶ所だけ。
StreamReaderを作るときにSystem.Text.Encoding.GetEncoding("Shift_JIS")を渡してやるようにするだけ。 このEncodingクラスがShift_JIS→Unicodeの変換をすべて面倒見てくれます。
(System.Text.ってネームスペース名を明示してるのは、単にこれだけのためにusingを追加するのが面倒だっただけ。 最初にusing System.Text;って入れておけば、もちろん、Encoding.GetEncoding("Shift_JIS")だけでOKです)

もちろん、Shift_JISだけじゃなくiso-2022-jpとかeuc-jpとかほとんどの文字コード用のEncodingクラスが用意されています。 当然、中国語やら韓国語やらもあります(と思う。試してません)。

あとはファイルの書き込み

あとはファイルの書き込みなんかを実装すればメモ帳の出来上がりです(出来上がりというのは、いくらなんでも言い過ぎか?)。
この辺は、読み込みとほとんど同じ要領なのでご自分でどうぞ。


[トップ] [目次] [←前] [次→]

株式会社ディーバ 青柳 臣一
2002/03/05