午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

WPFとVB.NETでデータをシリアライズしてZipファイルに保存

 
データをシリアライズしてZipファイルにして保存してから
逆方向の
保存したZipファイルを読み込んでデシリアライズしてデータに戻すまでの処理
ゲームのセーブとロードみたいなのをPixtack紫陽花2ndでも使いたいってのが目的
 
Zipファイルを扱うには準備が必要
System.IO.Compressionを参照の追加に追加する

f:id:gogowaten:20191025125946p:plain

ソリューションエクスプローラー→参照を右クリック→参照の追加→
参照マネージャーが開くのでアセンブリフレームワークを選択→
検索窓にcompreでSystem.IO.Compressionが見つかるのでチェック入れてOK
これで
イメージ 2
参照に追加された
 
デザイン画面とXAML

f:id:gogowaten:20191025130003p:plain

今回はこっちは使わないので初期状態
 
VBコード

f:id:gogowaten:20191025130012p:plain

Imports System.IO
Imports System.Runtime.Serialization
Imports System.IO.Compression

Class MainWindow
    Private Sub MainWindow_Initialized(sender As Object, e As EventArgs) Handles Me.Initialized
        'データ作成
        Dim AllSaveData As New List(Of SaveData)
        With AllSaveData
            .Add(New SaveData("どうのつるぎ", 70, 114.514))
            .Add(New SaveData("てつのやり", 560, 810))
        End With

        'シリアライズしてZipファイルに保存、
        '保存場所はアプリの実行ファイルと同じフォルダ、ファイル名はSave1.zipの場合
        Dim zipPath As String = My.Application.Info.DirectoryPath & "\" & "Save1.zip"
        Using ms As New MemoryStream
            'シリアライズ
            Dim bf As New Formatters.Binary.BinaryFormatter
            bf.Serialize(ms, AllSaveData)
            'Zipファイル作成
            Using ZipStream As Stream = File.Create(zipPath)
                Using archive As New ZipArchive(ZipStream, ZipArchiveMode.Create)
                    'Zipファイルの中身作成、名前がsave.binの場合
                    Dim entry As ZipArchiveEntry = archive.CreateEntry("save.bin")
                    Using entryStream As Stream = entry.Open
                        ms.Position = 0 'よくわかんないけど重要
                        ms.CopyTo(entryStream) 'シリアライズしたデータをZipファイルの中身にコピー
                    End Using
                End Using
            End Using
        End Using

        '保存したZipファイルの中からデータを取り出してデシリアライズ
        Dim SaveDataFromZip As New List(Of SaveData) 'データの入れ物
        'ZipファイルをStreamに読み込む
        Using zipStream As Stream = File.OpenRead(zipPath) ' File.Open(zipPath, FileMode.Open)
            Using archive As New ZipArchive(zipStream, ZipArchiveMode.Read)
                'Zipファイルの中のsave.binを取り出す
                Dim entry As ZipArchiveEntry = archive.GetEntry("save.bin")
                Using entryStream As Stream = entry.Open
                    Using ms As New MemoryStream
                        entryStream.CopyTo(ms) 'データをコピー
                        ms.Position = 0 '重要!!!!!
                        'デシリアライズ
                        Dim bf As New Formatters.Binary.BinaryFormatter
                        SaveDataFromZip = bf.Deserialize(ms)
                    End Using
                End Using
            End Using
        End Using
    End Sub
End Class
<Serializable>
Public Class SaveData
    Public Property namae As String
    Public Property kakaku価格 As Integer
    Public Property kougeki攻撃力 As Double
    Public Sub New(name As String, price As Integer, power As Double)
        namae = name
        kakaku価格 = price
        kougeki攻撃力 = power
    End Sub
End Class
これを実行すると
アプリの実行ファイルと同じフォルダにSave1.zipというファイルが作成される
この中にはsave.binというファイルが入っていて、これがシリアライズされたデータになっている
 
イメージ 5
保存するデータになる部分のクラス、名前はSaveDataにした
データの型はString、Integer、Doubleにしたけどシリアライズできる型なら何でもいい
 
イメージ 6
SaveDataを2つ作成してリストに入れる、このリストをシリアライズしてZipにして保存することになる
リストの名前はAllSaveDataをにした
 
イメージ 7
AllSaveDataをシリアライズしてZipにして保存
リストをシリアライズしたものをMemoryStreamに入れておいて
ZipArchiveってのがZipファイルになって
ZipArchiveEntryってのがZipファイルの中身の一つ一つになる感じかなあ
で、そのZipArchiveEntryにMemoryStreamをコピー
コピーする前にMemoryStreamのPositionを0(先頭?)にしないとエラーになる
 
ここまでの処理でZipファイルが作成される
イメージ 8
アプリの実行ファイルと同じフォルダにSave1.zipファイルが作成される
中にはsave.binが入っている
メモ帳とかで開いてみると
 

f:id:gogowaten:20191025130032p:plain

それっぽいものが記録されている、それにアプリの名前とかバージョンも記録されているみたいだけど要らないなあ
これを読み込むのが次の処理
 
イメージ 10
さっきの処理の逆になる感じ、かなあ
読み込んでデシリアライズしたデータは
SaveDataFromZipって名前をつけたリストに入れた
この中身がAllSaveDataと同じになっていれば成功ってことになる
 
 

f:id:gogowaten:20191025130044p:plain

データをシリアライズしてZipファイルに保存したところで一時停止したところ
ここから処理を進めて
 

f:id:gogowaten:20191025130053p:plain

保存したZipファイルからデータを読み込んだところ
元のデータAllSaveDataと読み込んだデータのSaveDataFromZipの中身が同じなので期待通りの動作!
 
シリアライズできる型やクラスならわざわざZipにする必要ないんだけど
目的は複数画像(BitmapSource)と画像それぞれの表示位置とかのデータを1つのファイルに保存したいってことで、そのためにはZipファイルに固めるのがいいかなあと思ったから今回のテストアプリ
次回は画像も含めたものでテスト↓

gogowaten.hatenablog.com

 
WPFVBで複数画像(BitmapSource)とシリアライズした文字列(String)や数値(Integerとか)を1つのZipファイルにする ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14079902.html
 
今回はいつにも増してよくわかっていなくて
とくにStream関係がわからん
 
 
参照したところ
System.IO.Compression.ZipArchive - Programming/.NET Framework/クラスライブラリ - 総武ソフトウェア推進所
http://smdn.jp/programming/netfx/fcl/System.IO.Compression.ZipArchive/
ストリーム - Programming/.NET Framework - 総武ソフトウェア推進所
http://smdn.jp/programming/netfx/stream/
 
今回のコード