none
設定ファイルの作成 RRS feed

  • 質問

  • お世話になります。

     

    起動時に設定ファイルから値を読み取り、終了時に設定ファイルに値を書き込むアプリケーションを作成しています。
    読み込み時"アプリケーション名.exe.config"が存在しない場合(ユーザーが誤って削除したときなど)は

    値がデフォルト設定になるようにしているのですが、終了時に保存する際エラーが出てしまいます。
    ファイルが存在しないときexe.configを作成するにはどうすればいいのでしょうか?

     

    XML形式のファイルの作成方法は心得ているつもりですが、どのクラスをもとにファイルを作成したらいいのかわかりません。

    "アプリケーション名.Properties.Settings"はパブリック型でないのでエラーが出てしまいます・・・

     

    見当違いな質問をしているかもしれませんが、何か解決のヒントだけでもいただけると恐縮です。

    2008年11月2日 17:25

回答

  •  紅葉 さんからの引用

    起動時に設定ファイルから値を読み取り、終了時に設定ファイルに値を書き込むアプリケーションを作成しています。

     

    根本的な問題として、この「書き込む」処理はどのように作成されているのでしょうか?

     

    アプリケーション構成ファイルは、Settings セクション以外にも様々な用途があり、それらの設定項目が記載されている読み取り専用の構成ファイルです。標準の Properties.Settings でも、読み取り専用の実装がされているため、Visual Studio で作成したアプリケーション設定のうち、アプリケーションスコープの要素については読み取り専用になっていて、ユーザースコープの要素については各ユーザのローカル設定として user.config に保存されます。

     

    このため、通常は C.John さんの書かれているような状態になると思います。

     

    内容をみるからに、

     

    ・ユーザースコープの設定情報を、app.config に保存したい

    ・app.config が何らかの理由で消失した際に、再構築したい

     

    という要件が混ざっているように見えます。

     

    前者に関しては、マルチユーザ環境やプログラム配置先のアクセス権限の設定などに準拠して行わないというのが方向性としてはありますが、アプリケーションの伝統的なスタイルとしてそういった構造にしたいという要求もあるので、調べてみると具体的な方法もみつかるのではないかと思います。(探してないんですけど)

     

    後者については、前述のようにアプリケーション構成ファイルの役割として、設定の保持以外の部分が大きいため、運用として app.config が消失した場合には、アプリケーションの修復セットアップまたは再インストールを要求するのが推奨されるスタイルになるのではないかと思います。

     

    それはちょっと大げさだという形であれば、安易な方法としては復旧イメージとなる app.config のスナップショットをリソースとして保持しておき、ファイルが存在しない場合にはリソースからファイルを生成しなおすという手段なんかが考えられます。

    2008年11月4日 14:49
  • こんばんは!(^^)!ふ~です。

    何かのメソッドで一発で復元できれば良いのでしょうが残念ながらそのようには設計されていませんね。

    復元ファイルが外部にあると消される事が心配であれば、プログラム内部に定数で持てば良さそうです。

    それを基に設定ファイルは何時でも作れます。

    参考資料 C#で設定する。

    http://www.microsoft.com/japan/msdn/vs05/vcsharp/SettingsCS_RL.aspx

     

    2008年11月4日 18:05

すべての返信

  •  紅葉 さんからの引用

    値がデフォルト設定になるようにしているのですが、終了時に保存する際エラーが出てしまいます。

    どのようなエラーが出るのでしょうか?(例外ですよね?)

     

    書いたコードもご提示頂けると、解決への時間短縮になる可能性があります。

     

     紅葉 さんからの引用

    XML形式のファイルの作成方法は心得ているつもりですが、どのクラスをもとにファイルを作成したらいいのかわかりません。

    "アプリケーション名.Properties.Settings"はパブリック型でないのでエラーが出てしまいます・・・

    XmlSerializerを使おうとしているのでしょうか?

    構成ファイルの保存・読み出しには通常使用しません。
    2008年11月3日 13:32
    モデレータ
  • ご返答ありがとうございます。

     

     Azulean さんからの引用

    どのようなエラーが出るのでしょうか?(例外ですよね?)

     

    書いたコードもご提示頂けると、解決への時間短縮になる可能性があります。

    以下のようなコードです。

    Code Snippet

    int X;

    private void Form1_Load(object sender, EventArgs e)
    {
        string fileName = System.IO.Directory.GetCurrentDirectory() +

                              @"\アプリケーション名.exe.config";

        if (System.IO.File.Exists(fileName) == true)
        {

              textBox1.Text = Properties.Settings.Default.Message;

              X = Properties.Settings.Default.X;
        }
        else
        {
            textBox1.Text = "メッセージ";
            X = 5;
        }
    }

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        Properties.Settings.Default.Message = this.textBox1.Text;
        Properties.Settings.Default.X = this.X;
        Properties.Settings.Default.Save();
    }

     

     

    コントロール(textBox1)はプロパティのApplicationSettingsを使用すると起動時にSettings.Designer.csで"ConfigurationErrosExceptionはハンドルされませんでした。"と表示されるため、Form1_Loadイベントで代入しています。

     

    実際にエラーが出るのは"Properties.Settings.Default.Save();"のところで、

    "ArgumentExceptionはハンドルされませんでした。"と表示されます。

    このエラーが出た後、再度設定ファイルを削除してからデバッグを実行すると上のエラー(ConfigurationErrosException)が表示されます。

     

    なお、デバッグ実行前にDebugフォルダのexe.config,vshost.exe.configを削除しています。

    デバッグ実行後どちらも自動で生成されるため、起動後もう一度削除しています。

    実際にアプリケーションを実行するときは自動で生成されることはありません…。

     

     Azulean さんからの引用

    XmlSerializerを使おうとしているのでしょうか?

    構成ファイルの保存・読み出しには通常使用しません。

    はい、XMLSerializerのことなのですが、ここでは使わないのですね。勉強になりました。
    2008年11月3日 15:37
  • こんにちは!(^^)!ふ~です。

     

    if (System.IO.File.Exists(fileName) == true)

        Properties.Settings.Default.Message = this.textBox1.Text;
        Properties.Settings.Default.X = this.X;
        Properties.Settings.Default.Save();


    エラーを表示しないようにするには、ファイルが無い場合には、Saveしなければ良いのです。!(^^)!

    どうも、何の為に、何をしたいのか、大分温度差があるようです。

    2008年11月4日 3:31
  • ご返答ありがとうございます。

     

     !(^^)!ふ~ さんからの引用

    エラーを表示しないようにするには、ファイルが無い場合には、Saveしなければ良いのです。

    はい。確かにそうすることでエラーは出なくなるのですが、それでは設定を保存するという本来の趣旨から外れてしまいます。

     

    私がやりたいことは、「textBox1.Text,int Xの変更を終了時に保存し、次回起動時にその変更を適用することでユーザーが再度変更する手間を省く」というものです。
    起動時にファイルがない場合はデフォルト設定にし、終了時に存在しない場合は作成してから保存する。というのが理想なのですが、可能でしょうか。

    2008年11月4日 7:37
  • こんばんは!(^^)!ふ~です。

    安全性を考慮するのは大変良いことですが、複雑に考えても仕方がない。ディレクトリを眺めるとバックアップファイルがあるようです。これを利用しても可能と思います。

     

    Code Snippet

    namespace WinApp_Properties_Settings
    {
     public partial class Form1 : Form
     {
      int X;

      // バックアップ設定ファイル
      string SrcFileName = System.IO.Directory.GetCurrentDirectory() +
         @"\WinApp_Properties_Settings.vshost.exe.config";

      // 通常設定ファイル
      string DestFileName = System.IO.Directory.GetCurrentDirectory() +
         @"\WinApp_Properties_Settings.exe.config";

      public Form1()
      {
       InitializeComponent();
      }

      private void Form1_Load(object sender, EventArgs e)
      {

       this.FormClosing += new FormClosingEventHandler(Form1_FormClosing);


       if (System.IO.File.Exists(DestFileName) == true)
       {

        textBox1.Text = Properties.Settings.Default.Message;

        X = Properties.Settings.Default.x;
       }
       else
       {
        textBox1.Text = "メッセージ";
        X = 5;
       }

      }

      private void Form1_FormClosing(object sender, FormClosingEventArgs e)
      {

       Properties.Settings.Default.Message = this.textBox1.Text;
       Properties.Settings.Default.x  = this.X;

       // 通常設定ファイルがあるか?
       if (System.IO.File.Exists(DestFileName) == true)
       {
        // 更新する。
        Properties.Settings.Default.Save();
       }
       else
       {
        // バックアップ設定ファイルから複写する。
        System.IO.File.Copy( SrcFileName, DestFileName );

        // 更新する。
        Properties.Settings.Default.Save();
       }
      }
     }
    }

     

    普通、設定ファイルWinApp_Properties_Settings.exe.configが消滅する事は無い筈です。また、バックアップファイルのWinApp_Properties_Settings.vshost.exe.configを、安全な場所に置いてあれば、復元できる分けですから、もっと、高級な創意工夫が可能と思います。ご参考になれば幸いです。

     

    2008年11月4日 11:16
  • 再度返答ありがとうございます。

     

    バックアップファイルから復元するというのも一つの手ではあると思いますが、オリジナル・バックアップともに消してしまったときは対処できないため、なんとか設定ファイルを作成できるようにしたいと考えています。
    前のご投稿の通り、ファイルがあるときのみ読み込み・保存を行えばエラーは出ないのですが、
    設定ファイルを削除してしまったら2度と設定を保存できないという状況を回避したいのです。

     

    改めて、解決方法をお教えいただければと思います。

    2008年11月4日 12:52
  • VisualC# 2008Express Editionで試してみましたが、exeと同じパスにconfigファイルが存在しない場合でもSaveで例外は返りませんでした。

    ただしexeと同じパスではなく下記のパスに保存されました。(Win2000の場合です)

    C:\Documents and Settings\ユーザー名\Local Settings\Application Data\(exeファイル名)\(バージョン)\user.config

     

    以下のページとは違うやり方をされたということでしょうか?

    http://www.microsoft.com/japan/msdn/vs05/vcsharp/SettingsCS_RL.aspx

    2008年11月4日 13:49
  •  C.John さんからの引用

    VisualC# 2008Express Editionで試してみましたが、exeと同じパスにconfigファイルが存在しない場合でもSaveで例外は返りませんでした。

    Professional Editionでも同様に例外はでませんでしたが、デバッグ実行のタイミングでうまくconfigファイルを消すと、起動時の例外は確認しました。

    ただ、予めファイルを消して、exeファイルを直接実行すると例外が発生しないことから、かなりタイミングに依存するのではないかと思っています。(詳細まで調べていません)

     

     

    configファイルを再生成するという考えは、最近のVistaのUACの絡みもありますし、辞めた方が良いのかもしれません。

    アプリケーションによってはconfigファイルを削除すると起動すらできないパターンもありますし、通常は再インストール(修復)となるのではないかと思います。

    (構成ファイルにアセンブリバインディングに関連する情報があり、それがないと起動できないなど)

    2008年11月4日 14:27
    モデレータ
  •  紅葉 さんからの引用

    起動時に設定ファイルから値を読み取り、終了時に設定ファイルに値を書き込むアプリケーションを作成しています。

     

    根本的な問題として、この「書き込む」処理はどのように作成されているのでしょうか?

     

    アプリケーション構成ファイルは、Settings セクション以外にも様々な用途があり、それらの設定項目が記載されている読み取り専用の構成ファイルです。標準の Properties.Settings でも、読み取り専用の実装がされているため、Visual Studio で作成したアプリケーション設定のうち、アプリケーションスコープの要素については読み取り専用になっていて、ユーザースコープの要素については各ユーザのローカル設定として user.config に保存されます。

     

    このため、通常は C.John さんの書かれているような状態になると思います。

     

    内容をみるからに、

     

    ・ユーザースコープの設定情報を、app.config に保存したい

    ・app.config が何らかの理由で消失した際に、再構築したい

     

    という要件が混ざっているように見えます。

     

    前者に関しては、マルチユーザ環境やプログラム配置先のアクセス権限の設定などに準拠して行わないというのが方向性としてはありますが、アプリケーションの伝統的なスタイルとしてそういった構造にしたいという要求もあるので、調べてみると具体的な方法もみつかるのではないかと思います。(探してないんですけど)

     

    後者については、前述のようにアプリケーション構成ファイルの役割として、設定の保持以外の部分が大きいため、運用として app.config が消失した場合には、アプリケーションの修復セットアップまたは再インストールを要求するのが推奨されるスタイルになるのではないかと思います。

     

    それはちょっと大げさだという形であれば、安易な方法としては復旧イメージとなる app.config のスナップショットをリソースとして保持しておき、ファイルが存在しない場合にはリソースからファイルを生成しなおすという手段なんかが考えられます。

    2008年11月4日 14:49
  • C.Johnさん、Azuleanさん、K.Takaokaさん、ご返答ありがとうございます。

     

    起動時、終了時ともにファイルの存在確認を行わないプログラムを新しく作成し、テストを行ってみました。


    [デバッグ実行時]
    configを削除してからデバッグ実行しても、問題なく起動しconfig自動生成。
    自動生成後再度削除すると、SaveでArgumentExceptionもしくは問題なく終了。デバッグ停止後config自動生成。
    エラーが出たときは、削除したのち再度実行するとConfigurationErrorsException。
    どういった状況だとエラーが出てどういった状況だと問題なく終了するのか、私にはわかりませんでした。
    [ビルド後exe実行時]
    configを削除してから実行しても問題なく起動・終了。
    configがある状態で起動し、実行中に削除すると、終了時にArgunmentExceptionでプログラム停止。
    その後configを戻さず起動しようとするとConfigurationErrorsExceptionでプログラム停止。
    一度エラーが出た場所、名前ではconfigを元に戻さないと2度と起動できないようです。(これも不確かです…)

     

    重要なことは何も得られませんでしたが、何かの参考にでもなれば幸いです。

     

     

     C.John さんからの引用

    ただしexeと同じパスではなく下記のパスに保存されました。(Win2000の場合です)
    C:\Documents and Settings\ユーザー名\Local Settings\Application Data\(exeファイル名)\(バージョン)\user.config

     K.Takaoka さんからの引用

    ユーザースコープの要素については各ユーザのローカル設定として user.config に保存されます。

    設定の変更がapp.configに保存されるという、完全に間違った解釈をしておりました。結局のところ私のやりたかったことは、
    ・app.config が何らかの理由で消失した際に、再構築したい です。
    上記のように削除しても問題なく起動・終了するときとエラーが出るときとありますが、
    ・削除しても問題なく起動・終了するときはapp.configを再構築しなくてもいいのか。
    ・エラーが出るとき再構築することは可能なのか(また、可能でもすべきでないのか)。

    お力添えをお願いします。

     

    追記(書き忘れ…)

    再構築の方法ですが、K.Takaokaさんの「リソースからファイルを生成しなおす」という手段を考えてみます。ありがとうございました。

    2008年11月4日 17:22
  • こんばんは!(^^)!ふ~です。

    何かのメソッドで一発で復元できれば良いのでしょうが残念ながらそのようには設計されていませんね。

    復元ファイルが外部にあると消される事が心配であれば、プログラム内部に定数で持てば良さそうです。

    それを基に設定ファイルは何時でも作れます。

    参考資料 C#で設定する。

    http://www.microsoft.com/japan/msdn/vs05/vcsharp/SettingsCS_RL.aspx

     

    2008年11月4日 18:05
  • 夜中にご返答ありがとうございます。

     

    もとが数KBの小さなアプリケーションだったためにリソースがアプリケーションの大半を占めることになりそうですが、内部に持つことで復元できるよう努力します。

    参考資料、再度ご提示いただきありがとうございます。参考になりました。

    2008年11月4日 18:14