DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

アプリケーションの設定を保存する

Visual Studio 2005以降で、アプリケーション設定機能を使用する

2005以降のVisual Studioを使っていれば、アプリケーションの設定の保存、復元が驚くほど簡単です。その方法は、「Visual Studioでアプリケーションの設定を保存する」で説明します。

Visual Studioを使っていなくても、.NET Framework 2.0からは、ApplicationSettingsBaseクラスを使って簡単に行うことができます。この方法は「ApplicationSettingsBaseクラスを使って設定を保存する」で説明します。

アプリケーションの設定を保存、復元するためのクラスを自作する

アプリケーション終了時に設定を保存しておき、次の起動時に設定を読み込むといった処理を行うためには、設定の情報をファイルに書き込むか、レジストリに書き込むかのどちらかの方法を選ぶことになるでしょう。ここではアプリケーションの設定を保存、復元するための様々な方法を考えます。

設定はクラスで管理する

アプリケーションの設定は、それぞれの設定をバラバラの変数に入れておくのではなく、すべての設定を一つのクラスにまとめて管理しておくと便利です。

ここでは、次のような"Settings"クラスを作成し、このクラスでアプリケーションの全設定(ここでは「Text」と「Number」の2つ)を管理するものとします。

VB.NET
コードを隠すコードを選択
Public Class Settings
    Private _text As String
    Private _number As Integer

    Public Property Text() As String
        Get
            Return _text
        End Get
        Set(ByVal Value As String)
            _text = Value
        End Set
    End Property

    Public Property Number() As Integer
        Get
            Return _number
        End Get
        Set(ByVal Value As Integer)
            _number = Value
        End Set
    End Property

    Public Sub New()
        _text = "Text"
        _number = 0
    End Sub
End Class
C#
コードを隠すコードを選択
public class Settings
{
    private string _text;
    private int _number;

    public string Text
    {
        get {return _text;}
        set {_text = value;}
    }
    public int Number
    {
        get {return _number;}
        set {_number = value;}
    }

    public Settings()
    {
        _text = "Text";
        _number = 0;
    }
}

XMLファイルに保存する

設定をファイルに保存する方法としては、WindowsではINIファイルがよく使用されていました。しかし.NET FrameworkではXMLの機能が充実していますので、XMLファイルに保存するのがよいでしょう。

補足:それでもINIファイルを使わなければならない場合は、INIファイルをテキストファイルとして扱うか、Win32 APIのGetPrivateProfileStringWritePrivateProfileString関数を使うかということになるでしょう。.NET FrameworkでINIファイルを扱うためのクラスとしては、「IniFile Class using VB.NET」、「An INI file handling class using C#」などが公開されています。

.NET FrameworkでXMLファイルを扱う方法にはいくつもありますが、「オブジェクトの内容をXMLファイルに保存、復元する」で紹介したように、設定を保存しているSettingsオブジェクトをXMLシリアル化する方法ならとても簡単です。

この方法でSettingsオブジェクト"appSettings"をXMLファイルに保存し、復元する簡単なコードを以下に示します。

VB.NET
コードを隠すコードを選択
Dim appSettings As New Settings

'保存先のファイル名
Dim fileName As String = "C:\test\settings.config"

'<XMLファイルに書き込む>
'XmlSerializerオブジェクトを作成
'書き込むオブジェクトの型を指定する
Dim serializer1 As New System.Xml.Serialization.XmlSerializer(GetType(Settings))
'ファイルを開く(UTF-8 BOM無し)
Dim sw As New System.IO.StreamWriter( _
    fileName, False, New System.Text.UTF8Encoding(False))
'シリアル化し、XMLファイルに保存する
serializer1.Serialize(sw, appSettings)
'閉じる
sw.Close()

'<XMLファイルから読み込む>
'XmlSerializerオブジェクトの作成
Dim serializer2 As New System.Xml.Serialization.XmlSerializer(GetType(Settings))
'ファイルを開く
Dim sr As New System.IO.StreamReader( _
    fileName, New System.Text.UTF8Encoding(False))
'XMLファイルから読み込み、逆シリアル化する
appSettings = CType(serializer2.Deserialize(sr), Settings)
'閉じる
sr.Close()
C#
コードを隠すコードを選択
Settings appSettings = new Settings();

//保存先のファイル名
string fileName = @"C:\test\settings.config";

//<XMLファイルに書き込む>
//XmlSerializerオブジェクトを作成
//書き込むオブジェクトの型を指定する
System.Xml.Serialization.XmlSerializer serializer1 =
    new System.Xml.Serialization.XmlSerializer(typeof(Settings));
//ファイルを開く(UTF-8 BOM無し)
System.IO.StreamWriter sw = new System.IO.StreamWriter(
    fileName, false, new System.Text.UTF8Encoding(false));
//シリアル化し、XMLファイルに保存する
serializer1.Serialize(sw, appSettings);
//閉じる
sw.Close();

//<XMLファイルから読み込む>
//XmlSerializerオブジェクトの作成
System.Xml.Serialization.XmlSerializer serializer2 =
    new System.Xml.Serialization.XmlSerializer(typeof(Settings));
//ファイルを開く
System.IO.StreamReader sr = new System.IO.StreamReader(
    fileName, new System.Text.UTF8Encoding(false));
//XMLファイルから読み込み、逆シリアル化する
appSettings =
    (Settings)serializer2.Deserialize(sr);
//閉じる
sr.Close();

バイナリファイルに保存する

設定をテキストファイルに保存する欠点として、その内容をユーザーが自由に編集できてしまうという点があります。それを防ぐためには、バイナリファイルに書き込む方法が考えられます(さらに、バイナリファイルを使ったほうが一般的に読み込み、書込みが速いです)。この方法は「オブジェクトの内容をバイナリファイルに保存、復元する」で説明しています。次はこの方法でやってみましょう。

まずは、SettingsクラスにSerializableAttributeを適用します。

VB.NET
コードを隠すコードを選択
<Serializable()> _
Public Class Settings
    '(省略)
End Class
C#
コードを隠すコードを選択
[Serializable()]
public class Settings
{
    //(省略)
}

Settingsオブジェクト"appSettings"をバイナリファイルに保存し、復元するコードは、例えば次のようになります。

VB.NET
コードを隠すコードを選択
'Imports System.Runtime.Serialization
'Imports System.Runtime.Serialization.Formatters.Binary
'がソースファイルの一番上に書かれているものとする

Dim appSettings As New Settings

'保存先のファイル名
Dim fileName As String = "C:\test\settings.config"

'<バイナリファイルに書き込む>
'BinaryFormatterオブジェクトを作成
Dim bf1 As New BinaryFormatter
'ファイルを開く
Dim fs1 As New System.IO.FileStream(fileName, System.IO.FileMode.Create)
'シリアル化し、バイナリファイルに保存する
bf1.Serialize(fs1, appSettings)
'閉じる
fs1.Close()

'<バイナリファイルから読み込む>
'BinaryFormatterオブジェクトの作成
Dim bf2 As New BinaryFormatter
'ファイルを開く
Dim fs2 As New System.IO.FileStream(fileName, System.IO.FileMode.Open)
'バイナリファイルから読み込み、逆シリアル化する
appSettings = CType(bf2.Deserialize(fs2), Settings)
'閉じる
fs2.Close()
C#
コードを隠すコードを選択
//using System.Runtime.Serialization;
//using System.Runtime.Serialization.Formatters.Binary;
//がソースファイルの一番上に書かれているものとする

Settings appSettings = new Settings();

//保存先のファイル名
string fileName = @"C:\test\settings.config";

//<バイナリファイルに書き込む>
//BinaryFormatterオブジェクトを作成
BinaryFormatter bf1 = new BinaryFormatter();
//ファイルを開く
System.IO.FileStream fs1 =
    new System.IO.FileStream(fileName, System.IO.FileMode.Create);
//シリアル化し、バイナリファイルに保存する
bf1.Serialize(fs1, appSettings);
//閉じる
fs1.Close();

//<バイナリファイルから読み込む>
//BinaryFormatterオブジェクトの作成
BinaryFormatter bf2 = new BinaryFormatter();
//ファイルを開く
System.IO.FileStream fs2 =
    new System.IO.FileStream(fileName, System.IO.FileMode.Open);
//バイナリファイルから読み込み、逆シリアル化する
appSettings  = (Settings) bf2.Deserialize(fs2);
//閉じる
fs2.Close();

レジストリに保存する

設定を保存する場所としては、レジストリも考えられます。レジストリに書き込まれた情報はユーザーによって編集、削除される恐れが少なく、書き込みや読み込みが高速です。また、Windows 95からはINIファイルに代わる方法として推奨されていました(今でもそうかは分かりません)。ただ欠点も多いため(「Why aren't .NET "application settings" stored in the registry?」を参照)、今ではアプリケーション設定の保存場所としてはあまり使用されないようです。

レジストリにデータを書き込む方法とレジストリからデータを読み込む方法は、「レジストリの操作」で説明しています。しかし、設定を一つ一つレジストリに書き込むのは面倒です。今まで紹介してきた方法のように、設定をレジストリに保存することはできないものでしょうか?

これに対する答えが、Windows Forms FAQの「How do you persist any object in the registry」(リンク切れ)で紹介されています。ここで紹介されている方法は、BinaryFormatterによりオブジェクトをシリアル化し、得られたバイト型配列をレジストリに書き込むというものです。

この方法によりSettingsオブジェクト"appSettings"をレジストリに保存、復元するコードの例を以下に示します。

VB.NET
コードを隠すコードを選択
'Imports System.IO
'Imports System.Runtime.Serialization
'Imports System.Runtime.Serialization.Formatters.Binary
'がソースファイルの一番上に書かれているものとする

Dim appSettings As New Settings

'<レジストリに書き込む>
Dim ms1 As New MemoryStream
Dim bf1 As New BinaryFormatter
'シリアル化してMemoryStreamに書き込む
bf1.Serialize(ms1, appSettings)
'レジストリへ保存する
Dim regkey1 As Microsoft.Win32.RegistryKey = _
    Microsoft.Win32.Registry.CurrentUser.CreateSubKey("Software\test\subkey")
regkey1.SetValue("Settings", ms1.ToArray())
'閉じる
ms1.Close()
regkey1.Close()

'<レジストリから読み込む>
Dim bf2 As New BinaryFormatter
'レジストリから読み込む
Dim regkey2 As Microsoft.Win32.RegistryKey = _
    Microsoft.Win32.Registry.CurrentUser.OpenSubKey( _
        "Software\test\subkey", False)
Dim bs As Byte() = CType(regkey2.GetValue("Settings"), Byte())
'逆シリアル化して復元
Dim ms2 As New MemoryStream(bs, False)
appSettings = CType(bf2.Deserialize(ms2), Settings)
'閉じる
ms2.Close()
regkey2.Close()
C#
コードを隠すコードを選択
//using System.IO;
//using System.Runtime.Serialization;
//using System.Runtime.Serialization.Formatters.Binary;
//がソースファイルの一番上に書かれているものとする

Settings appSettings = new Settings();

//<レジストリに書き込む>
MemoryStream ms1 = new MemoryStream();
BinaryFormatter bf1 = new BinaryFormatter();
//シリアル化してMemoryStreamに書き込む
bf1.Serialize(ms1, appSettings);
//レジストリへ保存する
Microsoft.Win32.RegistryKey regkey1 =
    Microsoft.Win32.Registry.CurrentUser.CreateSubKey(@"Software\test\subkey");
regkey1.SetValue("Settings", ms1.ToArray());
//閉じる
ms1.Close();
regkey1.Close();

//<レジストリから読み込む>
BinaryFormatter bf2 = new BinaryFormatter();
//レジストリから読み込む
Microsoft.Win32.RegistryKey regkey2 =
    Microsoft.Win32.Registry.CurrentUser.OpenSubKey(
    @"Software\test\subkey", false);
byte[] bs = (byte[]) regkey2.GetValue("Settings");
//逆シリアル化して復元
MemoryStream ms2 = new MemoryStream(bs, false);
appSettings = (Settings) bf2.Deserialize(ms2);
//閉じる
ms2.Close();
regkey2.Close();

シリアル化の欠点

設定オブジェクトをシリアル化する方法は、とても簡単で便利です。反面、新しくプロパティを加えるとそれ以前に保存したファイルから設定を復元できなくなるかもしれないという欠点があります。つまり、バージョンアップにより新しい設定が増え、設定クラスに新しいプロパティが増えると、前のバージョンの設定が読み込めないかもしれません。

これを回避するためには、「DataContractSerializerで、上位下位互換性を保ってシリアル化、逆シリアル化できるようにする」で紹介している方法を使う、設定をHashtableのようなコレクションで管理する、DataSetとして設定を管理し、WriteXml、ReadXmlメソッドで書き込み、読み込みをする、シリアル化せずに一つ一つの設定を保存、復元するなどの方法が考えられます。

設定を保存するフォルダを決める

設定を保存する方法をいろいろ紹介しましたが、設定をどのフォルダ、またはレジストリキーに保存するかという問題が残っています。この問題を解決するためのプロパティがApplicationクラスにあります。

設定を保存するのに適切なフォルダのパスは、ApplicationクラスのUserAppDataPathプロパティLocalUserAppDataPathプロパティCommonAppDataPathプロパティで取得できます。

UserAppDataPathプロパティは、ユーザーのアプリケーションデータのパスを返しますので、ユーザー別に設定を保存するために使用します。具体的には、例えば、

C:\Documents and Settings\[UserName]\Application Data\[CompanyName]\[ProductName]\[ProductVersion]

のようなフォルダのパスを返します([CompanyName]、[ProductName]、[ProductVersion]はそれぞれアプリケーションのCompanyName、ProductName、ProductVersionで、[UserName]はユーザー名です)。

LocalUserAppDataPathプロパティは、非ローミングユーザー(ユーザープロファイルが格納されているシステムにログオンしたユーザー)のアプリケーションデータのパスを返します。具体的には、例えば、

C:\Documents and Settings\[UserName]\Local Settings\Application Data\[CompanyName]\[ProductName]\[ProductVersion]

のようなフォルダのパスを返します。

CommonAppDataPathプロパティは、すべてのユーザーが共有する設定を保存するために使用します。具体的には、例えば、

C:\Documents and Settings\All Users\Application Data\[CompanyName]\[ProductName]\[ProductVersion]

のようなフォルダのパスを返します。

通常設定ファイルの保存先としては、UserAppDataPathプロパティが返すパスを使えばよいでしょう。

設定を保存するレジストリキーを決める

設定を書き込むのに適切なレジストリキーは、ApplicationクラスのUserAppDataRegistryプロパティまたはCommonAppDataRegistryプロパティで取得できます。

UserAppDataRegistryプロパティは、ユーザー別に設定を保存するために使用します。具体的には、

HKEY_CURRENT_USER\Software\[CompanyName]\[ProductName]\[ProductVersion]

というキーのRegistryKeyオブジェクトを返します。

CommonAppDataRegistryプロパティは、ユーザー共通の設定を保存するために使用します。具体的には、

HKEY_LOCAL_MACHINE\Software\[CompanyName]\[ProductName]\[ProductVersion]

というキーのRegistryKeyオブジェクトを返します。

つまり、UserAppDataRegistryとCommonAppDataRegistryの違いは、ルートキーがHKEY_CURRENT_USERかHKEY_LOCAL_MACHINEかの違いです。通常は、UserAppDataRegistryに保存すればよいでしょう。

注意:Windows Vistaから導入されたUACを有効にしている場合は、CommonAppDataRegistryプロパティを呼び出すと、例外UnauthorizedAccessExceptionが発生する可能性があります。詳しくは、「Vista以降でUACが有効だとファイルの作成等に失敗する問題の対処法」をご覧ください。

ここで紹介したプロパティが返すパスは、すべて最後にアプリケーションのバージョンが付いています。よって、これらをそのまま使って設定を保存すると、バージョンごとに設定の保存先が変わるため、バージョンが変わると、前の設定を読み込めないということになります。これでは困るという時は、保存場所を自分で決めるか、バージョンが変わった時に、前のバージョンの設定を移動するようにするなどの工夫が必要になるでしょう。

補足:ここで紹介したプロパティから値を取得する時に、そのレジストリキーあるいはフォルダが存在しなかった場合、勝手に作成されます。
補足:ここで紹介したプロパティは、そのパスにアセンブリの会社名や製品名をそのまま使って生成しているため、アセンブリの会社名や製品名にファイル名として使えない文字が含まれている場合はエラーが発生しますし、"\"が使われている場合は予期せぬパスとなってしまいます。よって、アセンブリの会社名や製品名に不適切な文字が含まれていないことを確かにしてから、これらのプロパティを使用する必要があります。

まとめ

以上の知識を基にして、Settingsクラスを作り直してみます。

まず、SettingsクラスのインスタンスをSettingsクラスの静的プロパティ"Instance"で取得できるようにします。

さらに、Settingsクラスの静的メソッドにより、XMLファイル、バイナリファイル、さらにレジストリへの設定の保存と復元ができるようにしています。なお保存先のパスは、バージョンに依存しない場所にしています。

VB.NET
コードを隠すコードを選択
Imports System
Imports System.IO
Imports System.Text
Imports System.Runtime.Serialization
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Windows.Forms
Imports Microsoft.Win32

<Serializable()> _
Public Class Settings
    '設定を保存するフィールド
    Private _text As String
    Private _number As Integer

    '設定のプロパティ
    Public Property Text() As String
        Get
            Return _text
        End Get
        Set(ByVal Value As String)
            _text = Value
        End Set
    End Property

    Public Property Number() As Integer
        Get
            Return _number
        End Get
        Set(ByVal Value As Integer)
            _number = value
        End Set
    End Property

    'コンストラクタ
    Public Sub New()
        _text = "Text"
        _number = 0
    End Sub

    'Settingsクラスのただ一つのインスタンス
    <NonSerialized()> _
    Private Shared _instance As Settings
    <System.Xml.Serialization.XmlIgnore()> _
    Public Shared Property Instance() As Settings
        Get
            If _instance Is Nothing Then
                _instance = New Settings
            End If
            Return _instance
        End Get
        Set(ByVal Value As Settings)
            _instance = Value
        End Set
    End Property

    ''' <summary>
    ''' 設定をXMLファイルから読み込み復元する
    ''' </summary>
    Public Shared Sub LoadFromXmlFile()
        Dim p As String = GetSettingPath()

        Dim sr As New StreamReader(p, New UTF8Encoding(False))
        Dim xs As New System.Xml.Serialization.XmlSerializer(GetType(Settings))
        '読み込んで逆シリアル化する
        Dim obj As Object = xs.Deserialize(sr)
        sr.Close()

        Instance = CType(obj, Settings)
    End Sub

    ''' <summary>
    ''' 現在の設定をXMLファイルに保存する
    ''' </summary>
    Public Shared Sub SaveToXmlFile()
        Dim p As String = GetSettingPath()

        Dim sw As New StreamWriter(p, False, New UTF8Encoding(False))
        Dim xs As New System.Xml.Serialization.XmlSerializer(GetType(Settings))
        'シリアル化して書き込む
        xs.Serialize(sw, Instance)
        sw.Close()
    End Sub

    ''' <summary>
    ''' 設定をバイナリファイルから読み込み復元する
    ''' </summary>
    Public Shared Sub LoadFromBinaryFile()
        Dim p As String = GetSettingPath()

        Dim fs As New FileStream(p, FileMode.Open, FileAccess.Read)
        Dim bf As New BinaryFormatter
        '読み込んで逆シリアル化する
        Dim obj As Object = bf.Deserialize(fs)
        fs.Close()

        Instance = CType(obj, Settings)
    End Sub

    ''' <summary>
    ''' 現在の設定をバイナリファイルに保存する
    ''' </summary>
    Public Shared Sub SaveToBinaryFile()
        Dim p As String = GetSettingPath()

        Dim fs As New FileStream(p, FileMode.Create, FileAccess.Write)
        Dim bf As New BinaryFormatter
        'シリアル化して書き込む
        bf.Serialize(fs, Instance)
        fs.Close()
    End Sub

    ''' <summary>
    ''' 設定をレジストリから読み込み復元する
    ''' </summary>
    Public Shared Sub LoadFromRegistry()
        Dim bf As New BinaryFormatter
        'レジストリから読み込む
        Dim reg As RegistryKey = GetSettingRegistry()
        Dim bs As Byte() = CType(reg.GetValue(""), Byte())
        '逆シリアル化して復元
        Dim ms As New MemoryStream(bs, False)
        Instance = CType(bf.Deserialize(ms), Settings)
        '閉じる
        ms.Close()
        reg.Close()
    End Sub

    ''' <summary>
    ''' 現在の設定をレジストリに保存する
    ''' </summary>
    Public Shared Sub SaveToRegistry()
        Dim ms As New MemoryStream
        Dim bf As New BinaryFormatter
        'シリアル化してMemoryStreamに書き込む
        bf.Serialize(ms, Instance)
        'レジストリへ保存する
        Dim reg As RegistryKey = GetSettingRegistry()
        reg.SetValue("", ms.ToArray())
        '閉じる
        ms.Close()
        reg.Close()
    End Sub

    Private Shared Function GetSettingPath() As String
        Dim p As String = Path.Combine( _
            Environment.GetFolderPath( _
                Environment.SpecialFolder.ApplicationData), _
            Application.CompanyName + "\" + Application.ProductName _
            + "\" + Application.ProductName + ".config")
        Return p
    End Function

    Private Shared Function GetSettingRegistry() As RegistryKey
        Dim reg As RegistryKey = _
            Registry.CurrentUser.CreateSubKey( _
                ("Software\" + Application.CompanyName + _
                "\" + Application.ProductName))
        Return reg
    End Function
End Class
C#
コードを隠すコードを選択
using System;
using System.IO;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;
using Microsoft.Win32;

[Serializable()]
public class Settings
{
    //設定を保存するフィールド
    private string _text;
    private int _number;

    //設定のプロパティ
    public string Text
    {
        get {return _text;}
        set {_text = value;}
    }
    public int Number
    {
        get {return _number;}
        set {_number = value;}
    }

    //コンストラクタ
    public Settings()
    {
        _text = "Text";
        _number = 0;
    }

    //Settingsクラスのただ一つのインスタンス
    [NonSerialized()]
    private static Settings _instance;
    [System.Xml.Serialization.XmlIgnore]
    public static Settings Instance
    {
        get
        {
            if (_instance == null)
                _instance = new Settings();
            return _instance;
        }
        set {_instance = value;}
    }

    /// <summary>
    /// 設定をXMLファイルから読み込み復元する
    /// </summary>
    public static void LoadFromXmlFile()
    {
        string path = GetSettingPath();

        StreamReader sr = new StreamReader(fileName, new UTF8Encoding(false));
        System.Xml.Serialization.XmlSerializer xs =
            new System.Xml.Serialization.XmlSerializer(typeof(Settings));
        //読み込んで逆シリアル化する
        object obj = xs.Deserialize(sr);
        sr.Close();

        Instance = (Settings) obj;
    }

    /// <summary>
    /// 現在の設定をXMLファイルに保存する
    /// </summary>
    public static void SaveToXmlFile()
    {
        string path = GetSettingPath();

        StreamWriter sw = new StreamWriter(fileName, new UTF8Encoding(false));
        System.Xml.Serialization.XmlSerializer xs =
            new System.Xml.Serialization.XmlSerializer(typeof(Settings));
        //シリアル化して書き込む
        xs.Serialize(sw, Instance);
        sw.Close();
    }

    /// <summary>
    /// 設定をバイナリファイルから読み込み復元する
    /// </summary>
    public static void LoadFromBinaryFile()
    {
        string path = GetSettingPath();

        FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
        BinaryFormatter bf = new BinaryFormatter();
        //読み込んで逆シリアル化する
        object obj = bf.Deserialize(fs);
        fs.Close();

        Instance = (Settings) obj;
    }

    /// <summary>
    /// 現在の設定をバイナリファイルに保存する
    /// </summary>
    public static void SaveToBinaryFile()
    {
        string path = GetSettingPath();

        FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write);
        BinaryFormatter bf = new BinaryFormatter();
        //シリアル化して書き込む
        bf.Serialize(fs, Instance);
        fs.Close();
    }

    /// <summary>
    /// 設定をレジストリから読み込み復元する
    /// </summary>
    public static void LoadFromRegistry()
    {
        BinaryFormatter bf = new BinaryFormatter();
        //レジストリから読み込む
        RegistryKey reg = GetSettingRegistry();
        byte[] bs = (byte[]) reg.GetValue("");
        //逆シリアル化して復元
        MemoryStream ms = new MemoryStream(bs, false);
        Instance = (Settings) bf.Deserialize(ms);
        //閉じる
        ms.Close();
        reg.Close();
    }

    /// <summary>
    /// 現在の設定をレジストリに保存する
    /// </summary>
    public static void SaveToRegistry()
    {
        MemoryStream ms = new MemoryStream();
        BinaryFormatter bf = new BinaryFormatter();
        //シリアル化してMemoryStreamに書き込む
        bf.Serialize(ms, Instance);
        //レジストリへ保存する
        RegistryKey reg = GetSettingRegistry();
        reg.SetValue("", ms.ToArray());
        //閉じる
        ms.Close();
        reg.Close();
    }

    private static string GetSettingPath()
    {
        string path = Path.Combine(
            Environment.GetFolderPath(
                Environment.SpecialFolder.ApplicationData),
            Application.CompanyName + "\\" + Application.ProductName +
            "\\" + Application.ProductName + ".config");
        return path;
    }

    private static RegistryKey GetSettingRegistry()
    {
        RegistryKey reg = Registry.CurrentUser.CreateSubKey(
            "Software\\" + Application.CompanyName +
            "\\" + Application.ProductName);
        return reg;
    }
}

このクラスを使用して設定をXMLファイルに保存、復元するには、次のようにします。(設定を読み込む時、保存されたデータが無い場合はエラーが出ます。)

VB.NET
コードを隠すコードを選択
'設定を変更する
Settings.Instance.Number = 123
Settings.Instance.Text = "こんにちは"

'現在の設定をXMLファイルに保存する
Settings.SaveToXmlFile()

'XMLファイルから設定を読み込む
Settings.LoadFromXmlFile()
C#
コードを隠すコードを選択
//設定を変更する
Settings.Instance.Number = 123;
Settings.Instance.Text = "こんにちは";

//現在の設定をXMLファイルに保存する
Settings.SaveToXmlFile();

//XMLファイルから設定を読み込む
Settings.LoadFromXmlFile();

最後に

アプリケーションの設定を保存、復元する方法には、実に様々な方法があり、ここで紹介した以外にもまだまだあるでしょう。ここで紹介した方法よりもよい方法をご存知の方は、ご連絡いただければ幸いです。

補足:設定をファイルに保存する方法として、「アプリケーション構成ファイルを使用する方法」を考えた方もいらっしゃるかもしれません。しかしアプリケーション構成ファイルは基本的に読み込み専用ですので、アプリケーションのユーザー設定の保存方法としては適切ではありません。
  • 履歴:
  • 2007/3/23 Settingsクラスの使用例で、コメントとコードが合っていなかったのを修正。
  • 2011/11/29 UACを有効にしていると、CommonAppDataRegistryプロパティがうまく行かないことがあることを追記。
  • 2014/5/12 XmlSerializerで読み書きする時、FileStreamではなくStreamReaderとStreamWriterを使うようにした。説明の簡略化など。
  • 2014/8/19 SaveToXmlFileメソッドでStreamWriterとすべきところがStreamReaderとなっていた不具合を修正。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • このサイトで紹介されているコードの多くは、例外処理が省略されています。例外処理については、こちらをご覧ください。
  • コードの先頭に記述されている「Imports ??? がソースファイルの一番上に書かれているものとする」(C#では、「using ???; がソースファイルの一番上に書かれているものとする」)の意味が分からないという方は、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。