インスタンスをファイルに保存、読み出す方法(XMLフォーマット編)
自作クラスのインスタンスなどをXML形式で保存、読み出しをします。
準備
Windows版Visual Studio2019では、次の参照の追加をしてください。
System.Runtime.Serialization
サンプルクラスを作ります。
このクラスには、練習用サンプルとして次の型がメンバーとして含まれています。
- フィールド
- プロパティ
- Dictionary型
- List型
インスタンス毎でまとまったデータを扱いたいときに利用できます。
namespace LoadSaveSample
{
class Program
{
static void Main(string[] args)
{
}
}
class Player
{
public string Name;
public int Hp { get; set; }
public Dictionary<string, string> Soubi;
public List<string> Items;
}
}
サンプルクラスのインスタンスを作ります。
注意)Mainメソッドの部分のみ表記しています
Player型のインスタンスを作成、各メンバー初期値を設定しています。
static void Main(string[] args)
{
Player hero = new Player();
hero.Name = "さいたま";
hero.Hp = 1000;
hero.Soubi = new Dictionary<string, string>
{
["鎧"] = "鉄のヨロイ",
["兜"] = "鉄のカブト",
};
hero.Soubi.Add("刀", "鋼のつるぎ");
hero.Items = new List<string>
{
"banana",
"apple"
};
hero.Items.Add("orange");
}
DataContractSerializerによってシリアライズされるクラスに変更します。
(DataMember属性をつけるとシリアル化の対象になります。)
DataContractSerializer クラスを使用して、ある型のインスタンスを XML ストリームまたはドキュメントにシリアル化または逆シリアル化します。シリアライズ(インスタンスをファイルに読み書きできるように変換すること)のため、各メンバーに属性をつけます
// Name要素は必須ではありません。
[DataContract(Name = "プレイヤー")]
class Player
{
// プライベートでもDataMemberAttributeがあればシリアル化される
[DataMember]
public string Name;
[DataMember(Name = "ヒットポイント")]
public int Hp { get; set; }
[DataMember]
public Dictionary<string, string> Soubi;
[DataMember]
public List<string> Items;
}
保存
型のインスタンスを XML ストリームにシリアル化します。
var xml = new DataContractSerializer(typeof(Player));
ファイルへの保存
XMLストリームをファイルストリームで保存します。
作成した型でファイルに保存することができます。WriteObjectメソッドを使います。
using (var fs = new FileStream("Player.xml", FileMode.Create))
{
xml.WriteObject(fs, hero);
}
実行ファイルがある場所にPlayer.xmlファイルが作成されたことを確認します。
通常、¥bin¥Debugの中
<プレイヤー xmlns="http://schemas.datacontract.org/2004/07/LoadSaveSample"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Items xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:string>banana</a:string>
<a:string>apple</a:string>
<a:string>orange</a:string>
</Items>
<Name>さいたま</Name>
<Soubi xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:KeyValueOfstringstring>
<a:Key>鎧</a:Key>
<a:Value>鉄のヨロイ</a:Value>
</a:KeyValueOfstringstring>
<a:KeyValueOfstringstring>
<a:Key>兜</a:Key>
<a:Value>鉄のカブト</a:Value>
</a:KeyValueOfstringstring>
<a:KeyValueOfstringstring>
<a:Key>刀</a:Key>
<a:Value>鋼のつるぎ</a:Value>
</a:KeyValueOfstringstring>
</Soubi>
<ヒットポイント>1000</ヒットポイント>
</プレイヤー>
読み出し
ファイルからの読み出し
XmlDictionaryReader型の変数にファイルから読み出したデータを代入します。
// ファイルから読み出し
XmlDictionaryReader reader;
using (var fs = new FileStream("Player.xml", FileMode.Open))
{
reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
}
データをデシリアライズし、インスタンスから読み取ります。(usingブロック内に記述)
hero = (Player)xml.ReadObject(reader, true);
すべてのコードについて
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
namespace LoadSaveSample
{
class Program
{
static void Main(string[] args)
{
Player hero = new Player();
hero.Name = "さいたま";
hero.Hp = 1000;
hero.Soubi = new Dictionary<string, string>
{
["鎧"] = "鉄のヨロイ",
["兜"] = "鉄のカブト",
};
hero.Soubi.Add("刀", "鋼のつるぎ");
hero.Items = new List<string>
{
"banana",
"apple"
};
hero.Items.Add("orange");
// 型のインスタンスを XML ストリームにシリアル化します。
var xml = new DataContractSerializer(typeof(Player));
// ファイルへの書き込み
using (var fs = new FileStream("Player.xml", FileMode.Create))
{
xml.WriteObject(fs, hero);
}
// ファイルから読み出し
XmlDictionaryReader reader;
using (var fs = new FileStream("Player.xml", FileMode.Open))
{
reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
// データをデシリアライズし、インスタンスから読み取ります。
hero = (Player)xml.ReadObject(reader, true);
}
}
}
// DataContractAttributeまたはSerializableAttributeを適用する必要があります
// DataContractSerializerによってシリアライズされるクラスに変換します。
// Name要素は必須ではありません。
[DataContract(Name = "プレイヤー")]
class Player
{
// プライベートでもDataMemberAttributeがあればシリアル化される
[DataMember]
public string Name;
[DataMember(Name = "ヒットポイント")]
public int Hp { get; set; }
[DataMember]
public Dictionary<string, string> Soubi;
[DataMember]
public List<string> Items;
}
}
データ コントラクト シリアライザーでサポートされる型
リファクタリングサンプル
リファクタリングポイント
- Playerインスタンスの初期化をコンストラクタで実施
- ロードとセーブをXMLクラス(Static)を作成し、移動
- 各処理のメソッド化
- 複数の方の処理ができるようにメソッドはジェネリックに変更
- Player型(自作型)以外のList型,Dictionary型での動作の確認
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Xml;
namespace LoadSaveSample
{
class Program
{
static void Main()
{
#region インスタンスに設定する各初期値の代入
var name = "さいたま";
var hp = 1000;
// equipmentは、日本語で「装備」
var equipments = new Dictionary<string, string>
{
["鎧"] = "鉄のヨロイ",
["兜"] = "鉄のカブト"
};
var items = new List<string>
{
"banana",
"apple"
};
#endregion
#region Playerクラスのインスタンを作成(インスタンス名は hero)
// 初期値はコンストラクタで代入するパターン
var hero = new Player(name, hp, equipments, items);
List<Viecle> viecles = new List<Viecle>
{
new Viecle { Name = "フェラーリ", Power = 500 },
new Viecle { Name = "ポルシェ", Power = 300 }
};
hero.Viecles = viecles;
// データ追加サンプル
hero.Equipments.Add("刀", "鋼のつるぎ");
hero.Items.Add("orange");
hero.Viecles.Add(new Viecle { Name = "ランボルギーニ", Power = 1000 });
#endregion
#region ロード、セーブ
// セーブ、ロード用のファイル名
var PlayerClassFileName = "Player.xml";
// 保存(セーブ)引数はインスタンスとファイル名。ジェネリックで型を指定
// XMLクラスはStaticなのでインスタンスにする必要はない(new でインスタンスを作成しない)
// XML.Save<Player>(hero, PlayerClassFileName);
// ジェネリック型は次のように省略できる
XML.Save(hero, PlayerClassFileName);
// 読み出し(ロード)引数はファイル名。ジェネリックで型を指定
var loadHero = XML.Load<Player>(PlayerClassFileName);
#endregion
#region 確認のためのコンソール表示
// 確認のためのコンソール表示(HpとName)
Console.WriteLine($"ヒーローの名前:{loadHero.PlayerName} \nヒットポイント:{loadHero.Hp}");
// 確認のためのコンソール表示(loadHeroのDictionary)
Console.WriteLine("\n*loadHeroの装備一覧");
foreach (var equipment in loadHero.Equipments)
{
Console.WriteLine($"{equipment.Key} -> {equipment.Value}");
}
// 確認のためのコンソール表示(loadHeroのList)
Console.WriteLine("\n*loadHeroのアイテム一覧");
foreach (var item in loadHero.Items)
{
Console.WriteLine($"{item}");
}
// 確認のためのコンソール表示(loadHeroのList<Viecle>)
Console.WriteLine("\n*loadHeroの乗り物一覧");
foreach (var vc in loadHero.Viecles)
{
Console.WriteLine($"車種 {vc.Name} :馬力 {vc.Power}");
}
#endregion
#region 色々な型で確認
// Dictionary型で確認
var DictionaryTypeFileName = "Equipments.xml";
XML.Save(equipments, DictionaryTypeFileName);
var loadEquipments = XML.Load<Dictionary<string, string>>(DictionaryTypeFileName);
// 確認のためのコンソール表示(Dictionary)
Console.WriteLine("\n*(確認)装備だけの一覧");
// LINQを使って表示(あくまで参考。ここまで必要ありません)
loadEquipments.ToList().ForEach(keyPair => Console.WriteLine($"{keyPair.Key} {keyPair.Value}"));
// List型で確認
var ListTypeFileName = "Items.xml";
XML.Save(items, ListTypeFileName);
var loadItems = XML.Load<List<string>>(ListTypeFileName);
// 確認のためのコンソール表示(List)
Console.WriteLine("\n*(確認)アイテムだけの一覧");
// LINQを使って表示
loadItems.ForEach(Console.WriteLine);
// Viecle型で確認
var ViecleTypeFileName = "Viecle.xml";
XML.Save(viecles, ViecleTypeFileName);
var loadViecles = XML.Load<List<Viecle>>(ViecleTypeFileName);
// 確認のためのコンソール表示(List)
Console.WriteLine("\n*(確認)乗り物だけの一覧");
// LINQを使って表示
loadViecles.ForEach(x => Console.WriteLine($"{x.Name} : {x.Power}"));
#endregion
}
}
// DataContractAttributeまたはSerializableAttributeを適用する必要があります
// DataContractSerializerによってシリアライズされるクラスに変換します。
// Name要素は必須ではありません。
[DataContract(Name = "プレイヤー")]
class Player
{
// プライベートでもDataMemberAttributeがあればシリアル化される
[DataMember]
public string PlayerName { get; set; }
[DataMember(Name = "ヒットポイント")]
public int Hp { get; set; }
[DataMember]
public Dictionary<string, string> Equipments;
[DataMember]
public List<string> Items;
[DataMember]
public List<Viecle> Viecles;
public Player(
string name,
int hp,
Dictionary<string, string> equipments,
List<string> items)
{
PlayerName = name;
Hp = hp;
Equipments = equipments;
Items = items;
}
}
[DataContract(Name = "乗り物")]
public class Viecle
{
[DataMember]
public string Name { get; set; }
[DataMember]
public int Power { get; set; }
}
// XMLフォーマット関連のクラス
static class XML
{
// ジェネリックメソッド
// T:タイプ(型)で、データ コントラクト シリアライザーでサポートされる型
public static void Save<T>(T instance, string fileName)
{
// 型のインスタンスを XML ストリームにシリアル化します。
var xml = new DataContractSerializer(typeof(T));
// ファイルへの書き込み
using (var fs = new FileStream(fileName,
FileMode.Create))
{
xml.WriteObject(fs, instance);
}
}
// ジェネリックメソッド
// T:タイプ(型)で、データ コントラクト シリアライザーでサポートされる型
// 戻り値も同じ型
public static T Load<T>(string fileName)
{
// 型のインスタンスを XML ストリームにシリアル化します。
var xml = new DataContractSerializer(typeof(T));
// ファイルから読み出し
XmlDictionaryReader reader;
using (var fs = new FileStream(fileName,
FileMode.Open))
{
reader = XmlDictionaryReader.CreateTextReader(
fs,
new XmlDictionaryReaderQuotas());
// データをデシリアライズし、インスタンスから読み取ります。
return (T)xml.ReadObject(reader, true);
}
}
}
}
/*
* データ コントラクト シリアライザーでサポートされる型
* https://docs.microsoft.com/ja-jp/dotnet/framework/wcf/feature-details/types-supported-by-the-data-contract-serializer?view=netframework-4.8
*/
Player.xml
<プレイヤー xmlns="http://schemas.datacontract.org/2004/07/LoadSaveSample"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Equipments xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:KeyValueOfstringstring>
<a:Key>鎧</a:Key>
<a:Value>鉄のヨロイ</a:Value>
</a:KeyValueOfstringstring>
<a:KeyValueOfstringstring>
<a:Key>兜</a:Key>
<a:Value>鉄のカブト</a:Value>
</a:KeyValueOfstringstring>
<a:KeyValueOfstringstring>
<a:Key>刀</a:Key>
<a:Value>鋼のつるぎ</a:Value>
</a:KeyValueOfstringstring>
</Equipments>
<Items xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:string>banana</a:string>
<a:string>apple</a:string>
<a:string>orange</a:string>
</Items>
<PlayerName>さいたま</PlayerName>
<Viecles>
<乗り物>
<Name>フェラーリ</Name>
<Power>500</Power>
</乗り物>
<乗り物>
<Name>ポルシェ</Name>
<Power>300</Power>
</乗り物>
<乗り物>
<Name>ランボルギーニ</Name>
<Power>1000</Power>
</乗り物>
</Viecles>
<ヒットポイント>1000</ヒットポイント>
</プレイヤー>
Equipments.xml
<ArrayOfKeyValueOfstringstring xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<KeyValueOfstringstring>
<Key>鎧</Key>
<Value>鉄のヨロイ</Value>
</KeyValueOfstringstring>
<KeyValueOfstringstring>
<Key>兜</Key>
<Value>鉄のカブト</Value>
</KeyValueOfstringstring>
<KeyValueOfstringstring>
<Key>刀</Key>
<Value>鋼のつるぎ</Value>
</KeyValueOfstringstring>
</ArrayOfKeyValueOfstringstring>
Items.xml
<ArrayOfstring xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<string>banana</string>
<string>apple</string>
<string>orange</string>
</ArrayOfstring>
Viecle.xml
<ArrayOf乗り物 xmlns="http://schemas.datacontract.org/2004/07/LoadSaveSample"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<乗り物>
<Name>フェラーリ</Name>
<Power>500</Power>
</乗り物>
<乗り物>
<Name>ポルシェ</Name>
<Power>300</Power>
</乗り物>
<乗り物>
<Name>ランボルギーニ</Name>
<Power>1000</Power>
</乗り物>
</ArrayOf乗り物>
ディスカッション
コメント一覧
まだ、コメントがありません