(C#)アプリケーションの設定を簡単に読み書きするクラス
作ったもの
アプリケーションの設定を簡単に読み書きするクラスを作りました。ウィンドウのサイズ、最後に開いたファイルなどを保存するのに使えます。
保存先は、AppData\Local\[会社名]\[アプリケーション名]です。
rcie.hatenablog.com
前提
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Reflection;
コード
/// <summary> /// 文字列でアプリケーションの設定を読み書きするクラス。 /// </summary> static class Config { private static Dictionary<string, string> dic; private static string path; static Config() { path = LocalAppData; Reload(); } /// <summary> /// キーに応じた値を取得する。 /// 存在しない場合は""を取得する。nullではない。 /// </summary> /// <param name="key">キー</param> /// <returns>値</returns> public static string Get(string key) { string value; return dic.TryGetValue(key, out value) ? (value ?? "") : ""; } /// <summary> /// キーに応じた値を整数値として取得する。 /// 存在しない場合はデフォルト値を取得する。 /// </summary> /// <param name="key">キー</param> /// <param name="defaultValue">キーが存在しない場合、整数値ではない場合のデフォルト値</param> /// <returns>整数値</returns> public static int GetInt(string key, int defaultValue = 0) { if (dic.ContainsKey(key)) { int n; return Int32.TryParse(dic[key], out n) ? n : defaultValue; } return defaultValue; } /// <summary> /// キーに応じた値を実数値として取得する。 /// 存在しない場合はデフォルト値を取得する。 /// </summary> /// <param name="key">キー</param> /// <param name="defaultValue">キーが存在しない場合、整数値ではない場合のデフォルト値</param> /// <returns>実数値</returns> public static double GetDouble(string key, double defaultValue = double.NaN) { if (dic.ContainsKey(key)) { double n; return Double.TryParse(dic[key], out n) ? n : defaultValue; } return defaultValue; } /// <summary> /// キーに対して値を設定する。 /// </summary> /// <param name="key">キー</param> /// <param name="value">値</param> public static void Set(string key, string value) { dic[key] = value; } /// <summary> /// AppData\Localの中にある設定保存用のディレクトリを取得します。 /// [ユーザー名]\AppData\Local\[会社名]\[アプリケーション名] /// 会社名が設定されていない場合は "Default" になります。 /// </summary> static private string LocalAppData { get { Func<string, bool> nameHasForbiddenChar = (str) => { foreach (var each in "\\/:*?\"<>|") { if (str.Contains(each + "")) { return true; } } return false; }; Assembly asm = Assembly.GetExecutingAssembly(); string asmName = asm.GetName().Name; Attribute customAttr = Attribute.GetCustomAttribute( asm, typeof(AssemblyCompanyAttribute)); string company = (customAttr as AssemblyCompanyAttribute).Company; if (company.Length == 0 || nameHasForbiddenChar(company)) { company = "Default"; } string path = Environment.GetFolderPath( Environment.SpecialFolder.LocalApplicationData); return path + "\\" + company + "\\" + asmName; } } /// <summary> /// 現在の状態を破棄して、設定ファイルから再度読み込む。 /// </summary> public static void Reload() { Directory.CreateDirectory(path); string configtxt = path + "\\config.txt"; try { string s = File.ReadAllText(configtxt, Encoding.UTF8); dic = StringからDictionaryへ(s); } catch (Exception) { dic = new Dictionary<string, string>(); } return; } /// <summary> /// 現在の状態を、設定ファイルに書き込む。 /// </summary> public static void Save() { Directory.CreateDirectory(path); string configtxt = path + "\\config.txt"; try { string s = DictionaryからStringへ(dic); File.WriteAllText(configtxt, s, Encoding.UTF8); } catch (Exception ex) { throw (ex); } return; } private enum Status { KEY, KEY_ESC, VALUE, VALUE_ESC, CR, END } private static Dictionary<string, string> StringからDictionaryへ(string s) { var sbKey = new StringBuilder(); var sbVal = new StringBuilder(); var result = new Dictionary<string, string>(); Status status = Status.KEY; Action<char> 行末処理 = (c) => { if (c == '\n' && sbKey.Length > 0 && sbVal.Length > 0) { result[sbKey.ToString()] = sbVal.ToString(); } sbKey.Clear(); sbVal.Clear(); status = Status.KEY; }; foreach (char c in s) { switch (status) { case Status.KEY: if (c == '\\') { status = Status.KEY_ESC; } else if (c == '=') { status = Status.VALUE; } else if (c == '\r') { status = Status.CR; } else { sbKey.Append(c); } continue; case Status.KEY_ESC: if (c == 'r') { sbKey.Append('\r'); } else if (c == 'n') { sbKey.Append('\n'); } else if (c == 't') { sbKey.Append('\t'); } else { sbKey.Append(c); } status = Status.KEY; continue; case Status.VALUE: if (c == '\\') { status = Status.VALUE_ESC; } else if (c == '\r') { status = Status.CR; } else { sbVal.Append(c); } continue; case Status.VALUE_ESC: if (c == 'r') { sbVal.Append('\r'); } else if (c == 'n') { sbVal.Append('\n'); } else if (c == 't') { sbVal.Append('\t'); } else { sbVal.Append(c); } status = Status.VALUE; continue; case Status.CR: 行末処理(c); continue; } } 行末処理('\n'); return result; } private static string DictionaryからStringへ(Dictionary<string, string> arg) { Func<string, string> Unescape = (s) => { if(s == null) { return ""; } var sb = new StringBuilder(); foreach (var c in s) { if (c == '=' || c == '\\') { sb.Append('\\').Append(c); } else if (c == '\r') { sb.Append("\\r"); } else if (c == '\n') { sb.Append("\\n"); } else if (c == '\t') { sb.Append("\\t"); } else { sb.Append(c); } } return sb.ToString(); }; var result = new StringBuilder(); foreach (var pair in arg) { var key = Unescape(pair.Key); if(key.Length == 0) { break; } var value = Unescape(pair.Value); if(value.Length == 0) { break; } if (result.Length > 0) { result.Append("\r\n"); } result.Append(key).Append('=').Append(value); } return result.ToString(); } }
使い方
string s = Config.Get("name"); // "name" というキーに対応する文字列の取得 int n = Config.GetInt("age", -1); // "age" というキーに対応する整数値の取得。キーがなければ -1 double d = Config.GetDouble("height"); // "height" というキーに対応する実数値の取得。キーがなければ NaN Config.Set("name", "太郎"); // "name" というキーに "太郎" を設定する Config.Save(); // C:\Users\[ユーザー名]\AppData\Local\[会社名]\[アプリケーション名]\config.txt に保存する