C#におけるシリアライズ・デシリアライズの方法|Javaでの方法についても解説!

- システム
エンジニア - XMLのシリアライズとは一体なんでしょうか?
- プロジェクト
マネージャー - XMLファイルを作成することをシリアライズと呼びます。では詳しくみていきましょう。
シリアライズ・デシリアライズとは?
今回はC#およびJavaにおけるシリアライズ・デシリアライズの方法を解説します。
まず、シリアライズとは何か説明します。シリアライズにはコンピュータ実行における意味とプログラミング言語における意味の2種類がありますが、今回は後者の解説となります。
なお、前者のコンピュータ実行における意味では「逐次化」と訳され、資源へのアクセス順序を調整することを指します。
プログラミング言語でのシリアライズ・デシリアライズ
では、プログラミング言語におけるシリアライズを説明します。
ここでのシリアライズは「直列化」と訳され、メインメモリ上に存在しているオブジェクトなどのデータを文字列やバイト列に変換することを指します。これには、ファイルとして保存したり、ネットワークで送受信したりできるようになるというメリットがあります。
逆に、シリアライズされたデータをもとの状態に復元することをデシリアライズと言います。
C#におけるXMLのシリアライズ・デシリアライズとは?
現在のソフトウェア開発において、XMLファイルは多くのシステムで使用されています。XMLファイルを作成することをシリアライズ、XMLファイルを読み込むことをデシリアライズと言います。C#でそれを行うにはどうしたら良いのでしょうか。
この記事ではまずXMLとは何か、という基本的なところから、C#でXMLをシリアライズ・デシリアライズする方法をわかりやすく解説します。XML初心者の方は是非ご覧ください。
C#でシリアライズ・デシリアライズに活用されるXMLとは
XMLとは以下のように<と>を使用したテキストファイルのフォーマットのことです。<と>の部分はタグと言います。Webページを記述する時に使うHTMLに似ています。
1 2 3 4 5 6 7 8 9 |
<ramen> <men>太麺</men> <soup>しょうゆ味</soup> <gu> <vegetable>ねぎ</vegetable> <meat>チャーシュー</meat> <egg>半熟味玉</egg> </gu> </ramen> |
Javaにおけるオブジェクトのシリアライズ・デシリアライズとは?
Javaでは専用のオブジェクト直列化ストリームプロトコルに従って、オブジェクトをシリアライズできます。こちらはC#のようなXML形式のテキストデータではなくバイナリデータで出力されます。テキストエディタ等でファイルの内容を見ても人間が理解できる形にはなっていません。
C#におけるXMLのシリアライズ・デシリアライズのやり方
では、C#でのシリアライズおよびデシリアライズのやり方をサンプルコードとともに解説していきます。ファイルが生成されることで実感もわきますので、是非実際に動かして確認してみてください。
C#におけるXMLのシリアライズのやり方2つ
以下のC#のサンプルは、上のラーメンのXMLをシリアライズします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
using System; using System.IO; using System.Text; using System.Xml.Serialization; namespace ConsoleApp1 { [XmlRoot(“ramen”)] public class Ramen { public Ramen() { // コンストラクタでGuのインスタンスを一緒に生成 Gu = new Gu(); } [XmlElement(“men”)] public string Men { get; set; } [XmlElement(“soup”)] public string Soup { get; set; } [XmlElement(“gu”)] public Gu Gu { get; set; } }; [XmlRoot(“gu”)] public class Gu { [XmlElement(“vegetable”)] public string Vegetable { get; set; } [XmlElement(“meat”)] public string Meat { get; set; } [XmlElement(“egg”)] public string Egg { get; set; } }; class Program { static void Main(string[] args) { var ramen = new Ramen(); ramen.Men = “太麺”; ramen.Soup = “しょうゆ味”; ramen.Gu.Vegetable = “ねぎ”; ramen.Gu.Meat = “チャーシュー”; ramen.Gu.Egg = “半熟味玉”; var xs = new XmlSerializer(typeof(Ramen)); using (var sw = new StreamWriter(“c:\\test\\ramen.xml”, false, Encoding.UTF8)) { xs.Serialize(sw, ramen); } } } } |
1:属性でタグの名前を指定できる
上のC#のサンプルを順に説明しましょう。まず、RamenとGuというクラスを定義しています。[XmlRoot(“~”)]と[XmlElement(“~”)]という属性を記述していますが、これによりXMLにシリアライズした時のタグの名前を指定できます。
属性で指定しない場合は、クラス名のRamenやプロパティ名のMenがそのまま使われます。ただしXMLのタグ名は先頭が小文字なことが通例なので、このように属性を使って変更しているのです。
2:XmlSerializerでシリアライズする
Mainメソッドでは、まずRamenクラスを生成しています。この時コンストラクタが呼ばれてRamen内部のGuのインスタンスも生成されます。
そしてMenなどのプロパティに文字列を代入しています。次にXmlSerializerクラスをRamenクラスを指定して生成し、using内でファイル書き込みを行うStreamWriterを生成します。StreamWriterの引数にはファイル名・追記するかどうか=false・文字エンコード=UTF8を指定しています。
usingを使用して安全にシリアライズできる
usingは{と}で囲った処理が終わった後に、後始末してくれるC#の機能です。このようなファイル制御で使用すればファイルのclose処理を自動的に行ってくれます。
{と}の中では、XmlSerializerに生成したRamenクラスとStreamWriterクラスを渡して、Serializeでシリアライズを行います。このC#サンプルを実行すればCドライブのtestフォルダにramen.xmlが作成されます。
C#におけるXMLのデシリアライズのやり方5つ
次は、C#でXMLファイルをデシリアライズする(読み込む)方法を説明します。ここまでのC#サンプルの、Mainメソッドを以下のように書き換えましょう。
1 2 3 4 5 6 7 8 9 10 11 12 |
static void Main(string[] args) { var xs = new XmlSerializer(typeof(Ramen)); Ramen ramen; using (var sr = new StreamReader(“c:\\test\\ramen.xml”, Encoding.UTF8)) using (var xr = System.Xml.XmlReader.Create(sr)) { ramen = (Ramen)xs.Deserialize(xr); // Ramenクラスにキャストする } Console.WriteLine(ramen.Men); Console.WriteLine(ramen.Gu.Egg); } |
1:XmlReaderでデシリアライズできる
上のC#サンプルを実行すると、以下のように表示されます。
1 2 |
太麺 半熟味玉 |
XmlSerializer・StreamReader・XmlReaderを使用することでramen.xmlをデシリアライズして、Ramenクラスのインスタンスとして読み込めていることがわかります。
2:XMLElementクラスでシリアライズ
ここまでのC#サンプルのRamenクラスのような、独自のクラスを作らずにXMLをシリアライズする場合はどうすればよいのでしょうか。その場合はXMLElementが便利です。Mainメソッドを以下のように書き換えてください。また「using System.Xml;」の追加も必要となります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
static void Main(string[] args) { XmlDocument xd = new XmlDocument(); XmlElement ramen = xd.CreateElement(“ramen”); XmlElement men = xd.CreateElement(“men”); men.InnerXml = “太麺”; ramen.AppendChild(men); XmlElement gu = xd.CreateElement(“gu”); XmlElement egg = xd.CreateElement(“egg”); egg.InnerXml = “半熟味玉”; gu.AppendChild(egg); ramen.AppendChild(gu); XmlSerializer xr = new XmlSerializer(typeof(XmlElement)); using (var sw = new StreamWriter(“c:\\test\\ramen.xml”, false, Encoding.UTF8)) { xr.Serialize(sw, ramen); } } |
3:AppendChildメソッドで追加が可能
上を実行するとramen.xmlファイルが生成されます。その中身は以下のようになります。
1 2 3 4 5 6 |
<ramen> <men>太麺</men> <gu> <egg>半熟味玉</egg> </gu> </ramen> |
XmlElementのAppendChildメソッドでXMLのツリー構造が実現できています。
4:XmlElementにデシリアライズ
XMLファイルをXmlElementの型にデシリアライズすることもできます。サンプルのMainメソッドを以下のように書き換えてください。
1 2 3 4 5 6 7 8 9 10 11 |
static void Main(string[] args) { var xs = new XmlSerializer(typeof(XmlElement)); XmlElement ramen; using (var sr = new StreamReader(“c:\\test\\ramen.xml”, Encoding.UTF8)) using (var xr = System.Xml.XmlReader.Create(sr)) { ramen = (XmlElement)xs.Deserialize(xr); // Ramenクラスにキャストする } Console.WriteLine(ramen.InnerXml); } |
5:独自クラスを使わずデシリアライズできる
上のサンプルを実行すると、
1 2 3 4 |
<men>太麺</men> <gu> <egg>半熟味玉</egg> </gu> |
と表示されます。XmlElement型のインスタンスとして取りこめていることがわかります。
Javaオブジェクトのシリアライズ・デシリアライズのやり方
ここまで、C#におけるシリアライズとデシリアライズのやり方を紹介してきました。
ですが、Javaにおいても同様にオブジェクトの内容をファイル出力する方法があります。
ここからは、Javaにおけるシリアライズとデシリアライズを紹介します。
クラスにSerializableインターフェイスを実装する
まずは、シリアライズしたいクラスの実装方法を紹介します。
以下はC#サンプルのRamenクラスとGuクラスをJavaで実装した場合の例となります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
import java.io.Serializable; public class Ramen implements Serializable { private String men; private String soup; private Gu gu; public Ramen() { // コンストラクタでGuのインスタンスを一緒に生成 gu = new Gu(); } public String getMen() { return men; } public void setMen(String men) { this.men = men; } public String getSoup() { return soup; } public void setSoup(String soup) { this.soup = soup; } public Gu getGu() { return gu; } public void setGu(Gu gu) { this.gu = gu; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
import java.io.Serializable; public class Gu implements Serializable { private String vegetable; private String meat; private String egg; public String getVegetable() { return vegetable; } public void setVegetable(String vegetable) { this.vegetable = vegetable; } public String getMeat() { return meat; } public void setMeat(String meat) { this.meat = meat; } public String getEgg() { return egg; } public void setEgg(String egg) { this.egg = egg; } } |
上の例では、シリアライズするオブジェクトであるRamenとGuというクラスにはSerializableインターフェイスを実装しています。シリアライズによってストリームに書き込めるオブジェクトはSerializableインターフェイスをサポートするものだけです。
なお、Serializableにメソッドおよびフィールドはなく、直列化可能であるという意味を識別する機能だけを備えています。
ObjectOutputStream・ObjectInputStreamを用いる
シリアライズでオブジェクトをファイル出力する場合、ObjectOutputStreamを使用します。これによって作成されたファイルをデシリアライズで読み込む場合、ObjectInputStreamを使用します。
ObjectOutputStreamによるシリアライズ
では、実際にJavaでのシリアライズ例を見ていきましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class Main { public static void main(String[] args) { Ramen ramen = new Ramen(); ramen.setMen("太麺"); ramen.setSoup("しょうゆ味"); ramen.getGu().setVegetable("ねぎ"); ramen.getGu().setMeat("チャーシュー"); ramen.getGu().setEgg("半熟味玉"); try (ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream("c:\\\\test\\\\ramen.bin"))) { oos.writeObject(ramen); } catch (IOException e) { e.printStackTrace(); } } } |
上の例では、まずRamenクラスを生成しています。この時コンストラクタが呼ばれてRamen内部のGuのインスタンスも生成されます。
そしてMenなどのプロパティに文字列を代入しています。次に、try-with-resources文でファイル書き込みを行うObjectOutputStreamを生成します。その後、writeObjectメソッドでRamenオブジェクトの内容をシリアライズして出力します。
ObjectInputStreamによるデシリアライズ
次は、Javaをデシリアライズする(読み込む)方法を説明します。ここまでのサンプルの、Mainクラスを以下のように書き換えましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class Main { public static void main(String[] args) { Ramen ramen = null; try (ObjectInputStream ois = new ObjectInputStream( new FileInputStream("c:\\\\test\\\\ramen.bin"))) { ramen = (Ramen) ois.readObject(); } catch (ClassNotFoundException | IOException e) { e.printStackTrace(); } System.out.println(ramen.getMen()); System.out.println(ramen.getGu().getEgg()); } } |
上のC#サンプルを実行すると、以下のように表示されます。
1 2 |
太麺 半熟味玉 |
これでファイルをデシリアライズして、Ramenクラスのインスタンスとして読み込めていることがわかります。
Javaでシリアライズ・デシリアライズする時の注意点
Javaでのシリアライズおよびデシリアライズのやり方を解説してきました。ただし、Javaでのデシリアライズでは制約事項となる注意点があります。それらについて、ここで紹介します。
対象オブジェクトの定義がないとエラーになる
上の例において、RamenクラスをRamen2クラスに名前変更して実行すると「java.lang.ClassNotFoundException:」というエラーが発生します。これは、シリアライズしたオブジェクトのクラスが存在しないことを示します。
また、GuクラスをGu2クラスに名前変更して実行してみましょう。すると、「java.io.InvalidClassException:」というエラーとなります。これは、シリアライズしたオブジェクトのクラスになんらかの不具合があったことを示します。RamenクラスでGuが見つからないことでこのようなエラーとなっています。
オブジェクトの定義内容を変更するとメソッドの定義までは復元不可
例のGuクラスにあるgetEggメソッドをmeatが戻り値となるよう変更して実行すると、結果は以下のようになります。
1 2 |
太麺 チャーシュー |
Guのオブジェクト内容は読み込めていますが、メソッド定義が変わったことで実行結果が変わってしまいます。このように、クラスの定義を変更すると結果が復元できなくなる場合があります。
- システム
エンジニア - HTMLに似ていますが、もっと効率的な方法なんですね。
- プロジェクト
マネージャー - その分奥の深い仕様ですが是非マスターして活用していきましょう。
C#のシリアライズでXMLを活用しよう
この記事でC#のXMLの扱いの基礎が理解できたのではないでしょうか。XMLには色々な仕様があり奥が深いですが、その分覚えれば大きく差がつきます。是非マスターしてXMLを活用してください。
C#やJavaでのシリアライズ・デシリアライズの方法を知ろう
この記事でC#におけるXML扱いの基礎が理解できたのではないでしょうか。XMLには色々な仕様があり奥が深いですが、その分覚えれば大きく差がつきます。是非マスターしてXMLを活用してください。
また、Javaにおけるシリアライズとデシリアライズの方法も紹介しました。是非マスターして活用してください。
FEnet.NETナビ・.NETコラムは株式会社オープンアップシステムが運営しています。
株式会社オープンアップシステムはこんな会社です
秋葉原オフィスには株式会社オープンアップシステムをはじめグループのIT企業が集結!
数多くのエンジニアが集まります。

-
スマホアプリから業務系システムまで
スマホアプリから業務系システムまで開発案件多数。システムエンジニア・プログラマーとしての多彩なキャリアパスがあります。
-
充実した研修制度
毎年、IT技術のトレンドや社員の要望に合わせて、カリキュラムを刷新し展開しています。社内講師の丁寧なサポートを受けながら、自分のペースで学ぶことができます。
-
資格取得を応援
スキルアップしたい社員を応援するために資格取得一時金制度を設けています。受験料(実費)と合わせて資格レベルに合わせた最大10万円の一時金も支給しています。
-
東証プライム上場企業グループ
オープンアップシステムは東証プライム上場「株式会社オープンアップグループ」のグループ企業です。
安定した経営基盤とグループ間のスムーズな連携でコロナ禍でも安定した雇用を実現させています。
株式会社オープンアップシステムに興味を持った方へ
株式会社オープンアップシステムでは、開発系エンジニア・プログラマを募集しています。
年収をアップしたい!スキルアップしたい!大手の上流案件にチャレンジしたい!
まずは話だけでも聞いてみたい場合もOK。お気軽にご登録ください。


C#新着案件New Job
システム開発/東京都新宿区/【WEB面談可/C#経験者/20代前半の方活躍中/経験1年以上の方活躍中】/在宅勤務
月給29万~34万円東京都新宿区(新宿駅)システム開発/東京都新宿区/【WEB面談可/C#経験者/20代後半~40代の方活躍中/経験年数不問】/在宅勤務
月給41万~50万円東京都新宿区(新宿駅)デバック、テスト項目の作成/神奈川県横浜市/【WEB面談可/C#経験者/20代前半の方活躍中/経験1年以上の方活躍中】/在宅勤務
月給29万~34万円神奈川県横浜市(桜木町駅)デバック、テスト項目の作成/神奈川県横浜市/【WEB面談可/C#経験者/20代後半~40代の方活躍中/経験年数不問】/在宅勤務
月給41万~50万円神奈川県横浜市(桜木町駅)基幹システム開発導入/東京都新宿区/【WEB面談可/C#経験者/20代前半の方活躍中/経験1年以上の方活躍中】/在宅勤務
月給29万~34万円東京都新宿区(西新宿駅)基幹システム開発導入/東京都新宿区/【WEB面談可/C#経験者/20代後半~40代の方活躍中/経験年数不問】/在宅勤務
月給41万~50万円東京都新宿区(西新宿駅)