2014年05月11日

設定ファイルから値を取得

   このエントリーをはてなブックマークに追加 Clip to Evernote
どう書く?orgに感謝を込めて」シリーズ その6

■問題 (出題者;syat さん) 
設定ファイルから項目名をキーとして値を取得するコードを書いてください。 設定ファイルのイメージも載せてください。 ここで設定ファイルとは、
・項目名と値のペアが書いてあるファイル
・フォーマットはその言語で扱いやすいものでよい
・コードと分離され、コードに影響を与えずに変更が可能
を条件とします。ファイルが難しければ同等のものでもかまいません(テーブル、環境変数など)。


.NETでの標準である configファイルを使ってみました。

■C#で書いたコード
using System;
using System.Configuration;
using System.Collections.Specialized;

namespace Doukaku.Org {
    class Program {

        static void Main(string[] args) {
            NameValueCollection settings = ConfigurationManager.AppSettings;

            // キーを指定して読み込む
            string price = settings["Orange"];
            Console.WriteLine("{0} = {1}", "Orange", price);


            // すべての設定値を読み込む
            foreach (var key in settings.AllKeys)
                Console.WriteLine("{0} = {1}",key , settings[key]);


            // こんな読み込み方法もある AppSettingsReaderクラスを使用
            AppSettingsReader reader = new AppSettingsReader();
            int val = (int)reader.GetValue("Peach", typeof(int));
            Console.WriteLine("{0} = {1}", "Peach", val);
        }
    }
}
  

Posted by gushwell at 22:30Comments(0)TrackBack(0)

2014年05月08日

データの圧縮と展開

   このエントリーをはてなブックマークに追加 Clip to Evernote
どう書く?orgに感謝を込めて」シリーズ その5

■問題 (出題者: 
mattsan さん)
データを圧縮するcompress、展開するdecompressという関数やメソッドなどを書いてください。データはバイト列でもストリームでもそれ以外の形式でもOKです。 圧縮形式は問いませんが、できるだけ一般的なフォーマット(zip,lzhなど)でお願いします。 また、標準以外のライブラリを使う場合には出典の記載をお願いします。 「○○でも実用的な圧縮/展開プログラムがかけるんだぞ!」というのを、ぜひ示してください。

文字列を圧縮、展開するメソッドを作成。 
お題では、一般的なフォーマットとありますが、このコードを書いた当時は、まだ、.NET Framework3.5 だったので、 .NET Framework4.5に追加されたZipArchiveは使ってない。 GZipStream を使ってバイト配列に圧縮。

ZIPファイルについては、メールマガジン「C#プログラミングレッスン」のバックナンバー No.379 を見てください。

■C#で書いたコード 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Compression;


namespace Doukaku.Org {
    class Program {
        static void Main(string[] args) {
            // 文字列をバイト配列に変換します
            string text = @"ある日の暮方の事である。一人の下人(げにん)が、羅生門(らしょうもん)の下で雨やみを待っていた。
広い門の下には、この男のほかに誰もいない。ただ、所々丹塗(にぬり)の剥(は)げた、大きな円柱(まるばしら)に、蟋蟀(きりぎりす)が一匹とまっている。羅生門が、朱雀大路(すざくおおじ)にある以上は、この男のほかにも、雨やみをする市女笠(いちめがさ)や揉烏帽子(もみえぼし)が、もう二三人はありそうなものである。それが、この男のほかには誰もいない。";

            byte[] destination = Compress(text);
            // 圧縮前と圧縮後の長さを比較します
            //Console.WriteLine(source.Length.ToString() + " vs " + ms.Length.ToString());

            // バイト配列を文字列に変換して表示します
            //Console.WriteLine(Encoding.Unicode.GetString(destination));

            string result = Decompress(destination);
            Console.WriteLine(result);
            Console.ReadLine();
        }

        private static string Decompress(byte[] destination) {
            using (MemoryStream ms = new MemoryStream(destination))
            using (GZipStream gzip = new GZipStream(ms, CompressionMode.Decompress)) {
                StringBuilder sb = new StringBuilder();
                byte[] buff = new byte[4096];
                int length = 0;
                while ((length = gzip.Read(buff, 0, buff.Length)) > 0) {
                    sb.Append(Encoding.Unicode.GetString(buff, 0, length));
                }
                return sb.ToString();
            };
        }

        private static byte[] Compress(string text) {
            byte[] source = Encoding.Unicode.GetBytes(text);

            // 入出力用のストリームを生成します
            using (MemoryStream ms = new MemoryStream())
            using (GZipStream gzip = new GZipStream(ms, CompressionMode.Compress)) {

                // ストリームに圧縮するデータを書き込みます
                gzip.Write(source, 0, source.Length);

                // 圧縮されたデータを バイト配列で取得します
                return ms.ToArray();
            }
        }
    }
}
  
Posted by gushwell at 23:00Comments(0)TrackBack(0)

2011年07月26日

アプリケーションの設定情報の扱いについて考えてみる(4)

   このエントリーをはてなブックマークに追加 Clip to Evernote
「アプリケーションの設定情報の扱いについて考えてみる」の4回目です。

■ ApplicationScopedSettingAttribute

[UserScopedSetting] の代わりに、[ApplicationScopedSetting]属性を付加すると、 ユーザ単位ではなく、
アプリケーションでひとつの(つまり、すべてのユーザーに対して共通の) 値を持つことができます。

しかし、この属性を付けた場合は、デフォルトの動作(LocalFileSettingsProviderの動作)では、読み取り専用となります。
値を変更し保存することができません。

この読み取り専用の設定情報は、app.config に記述することになります。
以下に、その例を示します。


なお、これを書きこみ可能とするには、System.Configuration.SettingsProvider を継承した独自のプロバイダークラスを
作成する必要がありますが、この作成方法については、省略します。
興味あるかたは、MSDN等で調べてください。
  
Posted by gushwell at 23:00Comments(0)TrackBack(0)

2011年07月24日

アプリケーションの設定情報の扱いについて考えてみる(3)

   このエントリーをはてなブックマークに追加 Clip to Evernote
「アプリケーションの設定情報の扱いについて考えてみる」 の3回目です。

■ バージョンアップ時に前バージョンの情報を引き継ぐ

アセンブリのバージョンが上がったときは、configファイルの保存場所が変更されることは前回説明しました。
これは何を意味するかというと、そのままでは、前バージョンの設定情報を取得することができないということです。
Windowsのサイズと位置程度ならば、初期状態に戻ってしまってもかまわないかもしれませんが、設定情報を引き継ぎたいということは、良くあることです。
この目的のために、ApplicationSettingsBase には、Upgradeというメソッドが用意されています。

しかし、何を基準にUpgradeを呼び出したら良いのかを判断する方法が用意されていないようです。
※ 調べましたが、見つけることができませんでした。

そのため、自前でバージョンが変更されたかどうかを判断するコードを書く必要があります。

ここでは、IsUpgraded というプロパティを WindowInfoに追加することで対応します。


このプロパティを使った、設定情報の読み込みを以下に示します。


これで、設定情報の引継ぎが可能になります。

2011/8/9 追記
IsUpgradedプロパティのコードが間違っていましたので、訂正しました。
  
Posted by gushwell at 21:00Comments(2)TrackBack(0)

2011年07月18日

アプリケーションの設定情報の扱いについて考えてみる(2)

   このエントリーをはてなブックマークに追加 Clip to Evernote
前回の続き

前回は、ApplicationSettingsBase クラスを継承した簡単なクラス定義例をお見せしました。
今回は、「デフォルト値の設定」と「保存場所とその形式」について簡単に解説します。

■ デフォルト値を設定する。

デフォルト値を設定するには、NullReferenceException 例外をキャッチし、そこで、値を設定する方法と、
属性でデフォルト値を設定する方法の2通りがあります。

属性でデフォルト値を設定するには、DefaultSettingValueAttribute 属性を指定します。

前回示したWindowInfoクラスを例に、そのコードを示します。


このようにすれば、設定ファイルが存在しない場合にも例外は発生しませんので、try-catchは不要になります。


■どこに保存されるのか

exeファイルが存在するフォルダをみても、それらしいファイルは存在していません。
では、どこに保存されているのかというと、Windows7では、


といった場所に保存されます。
アセンブリにCompanyNameが設定されていない場合は、exe名が CompanyNameになります。

1.0.0.0 は、アセンブリのバージョンを示します。
製品バージョンやファイルバージョンではなく、アセンブリのバージョンです。
アセンブリのバージョンが変わると、保存場所も変わります。
ビルド番号やリビジョン番号が変わっても保存場所は変わります。


■ 構成ファイルの形式

構成ファイルのサンプルを示します。

  
Posted by gushwell at 22:30Comments(0)TrackBack(0)

2011年07月10日

アプリケーションの設定情報の扱いについて考えてみる(1)

   このエントリーをはてなブックマークに追加 Clip to Evernote
■はじめに

アプリケーション独自の設定情報を扱いたい、そんな要求に答えるには、太古の昔は、INIファイルが定番でしたが、
いつしか、レジストリが主流になり、そして.NETでは、XML形式のconfigファイルへと移ってきました。

configファイルにアプリケーション独自の情報を設定するのに、もっとも手軽なのが、App.config の
要素を使う方法です。
ただ、これは、
・全てを文字列として扱う必要がある。
・項目を一つ一つ指定してアクセスする必要がある
など、柔軟性に欠ける部分があります。

そして、さらに問題となるのが、書き込みをしたいという要求にうまく対応できないということです。

そこで、数回にわけて、設定ファイルの読み書きについて考えてみます。

まずは、.NET Frameworkでそのために用意されていると思われるApplicationSettingsBaseクラス を使い、
アプリケーション独自の設定情報の読み書きについて考えてみます。

■ApplicationSettingsBaseクラスを利用した設定ファイルの読み書き

例えば、ウインドウのサイズと位置を保存しておきたいとしましょう。
当然、これらの値はひとつのクラスとして扱いたいですね。
例えば、


というクラスを考えてみます。
このクラスを 設定ファイルに保存できるようにするには、ApplicationSettingsBase から継承し、
以下のように書き換えてやる必要があります。


随分コードが増えてしまいましたが、パターン化されていますので、 機械的にコーディングできると思います。

このクラス定義ができれば、あとは読み書きのコードを書くだけです。


読み込みは、WindowInfo のオブジェクトを生成し、プロパティにアクセスするだけです。
なお、このプログラムを最初に起動した場合は、値を読み込むことが出来ないために、
NullReferenceException 例外が発生します。この例外が出たときには、何もせずにデザイン時の値を
そのまま使います。
書き込みは、WindowsInfoの各プロパティに値を設定し、Saveメソッドを呼び出します。

なお、WindowsFormsでは、フォームデザイナーのプロパティ画面で、(ApplicationSettings) で
保存したいプロパティを設定すれば、いちいち上記のようなコードを書く必要はありません。
あくまでも、サンプルとして見てください。

実際、自動生成される Settings.Designer.cs を見てみると、ApplicationSettingsBase クラスを継承したクラスが
定義されています。

もちろん、フォームやGUIコントロールのプロパティ以外の値を設定するには、デザイナーでのサポートは
ありませんので、ApplicationSettingsBaseクラスを利用するなら、ここに書いた方法で値を設定することになります。

(続く...)

追記 (2011/07/11)
最後の文は、ちょっと語弊がある文章でした。
C#プロジェクトの Properties フォルダの、Settings.settingsを開いて表示されるデザイナー(これもデザイナー
の一種ですね)で独自の情報を格納することができます。

ただ、このシリーズでは、Settings.settingsを開いて表示される設定デザイナーを利用する方法については、割愛します。

ApplicationSettingsBase を直接使ってみることで、Settings.settingsで作成する 設定ファイルクラスを
より理解できるようになります。

  
Posted by gushwell at 22:38Comments(0)TrackBack(0)